首页
碎碎念
东邻西舍
本站信息
前来吐槽
统计
Search
1
openwrt系统上安装第三方插件
27,288 阅读
2
ubuntu下zerotier的基本使用教程
14,542 阅读
3
给小米R3G更换系统:从padavan刷成openwrt
13,423 阅读
4
openwrt使用第一步:设置上网拨号
11,297 阅读
5
openwrt无线中继功能:实现不插网线就能上网
10,071 阅读
学习点滴
Java
Web前端
Linux
踩坑实录
折腾搞机
关于建站
只言片语
登录
Search
标签搜索
Linux
Java
建站
踩坑实录
Ubuntu
折腾搞机
MySQL
MyBatis
CSS
HTML
Spring
SQL
Nginx
OpenWrt
树莓派
路由器
Maven
SSL
Git
Windows
知识分子没文化
累计撰写
85
篇文章
累计收到
155
条评论
首页
栏目
学习点滴
Java
Web前端
Linux
踩坑实录
折腾搞机
关于建站
只言片语
页面
碎碎念
东邻西舍
本站信息
前来吐槽
统计
搜索到
17
篇与
的结果
2021-12-20
Spring Boot学习笔记
目录 一、Spring Boot简介 二、Spring Boot的主要特性 2.1、自动配置 2.2、起步依赖(Starters) 2.3、简化配置 2.4、内置服务器 2.5、无代码生成与 XML 配置 三、Spring Boot的配置 3.1、配置文件类型 3.1.1、application.properties 3.1.2、application.yaml(或.yml) 3.2、配置优先级 3.2.1、配置文件位置的优先级 3.2.2、配置文件格式的优先级 3.3、读取配置文件的方式 3.3.1、使用@Value注解 3.3.2、使用Environment对象 3.3.3、将部分配置封装成实体类 3.4、多环境开发时配置文件的切换 3.5、yml配置文件示例 四、整合MyBatis 4.1、添加起步依赖 4.2、添加配置 4.3、扫描Mapper接口 五、使用Maven打包Spring Boot项目 一、Spring Boot简介 Spring Boot 是 Spring 框架的一个扩展,旨在简化 Spring 应用的初始搭建和开发过程。它通过自动配置和约定优于配置的原则,提供一个开箱即用的应用程序架构,能够快速构建独立运行的 Spring 应用,开发者基于 Spring Boot 的预置结构继续开发,省时省力。 Spring Boot 官方文档:https://docs.spring.io/spring-boot/index.html Spring 中文网翻译的 Spring Boot 中文文档:https://springdoc.cn/spring-boot 通过 IDEA 创建 Spring Boot 项目: 添加核心依赖 Spring Web: 除了用 IDEA 创建 Spring Boot 项目,也可以直接访问 Spring Boot 项目生成网站,设定项目的元数据(如项目类型、语言、Spring Boot 版本等)之后,创建好的项目就会以压缩包的格式下载到本地,解压导入到开发工具即可。 Spring Boot 项目生成网站: https://start.spring.io/:Spring Boot 官方的项目生成工具,Java 版本和 Spring Boot 版本都比较新,国内有可能访问不了或访问速度比较慢 https://start.springboot.io/:官方项目生成工具的国内镜像,Java 版本和 Spring Boot 版本与官网一致,国内都能访问 https://start.aliyun.com/:从域名能看出来是阿里云镜像,国内都能访问,而且能用旧的 Java 版本和 Spring Boot 版本生成项目 一个典型的 Spring Boot 项目结构如下: SpringBoot-project/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── MyApplication.java │ │ └── resources/ │ │ ├── application.properties │ │ └── static/ │ │ └── templates/ │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── MyApplicationTests.java ├── pom.xml └── README.md MyApplication.java:Spring Boot 应用的主类,使用 @SpringBootApplication 注解标记。 application.properties:Spring Boot 应用的配置文件,可以配置各种属性。 static/:存放静态资源文件,例如 HTML、CSS、JavaScript 文件等。 templates/:存放模板文件,例如 Thymeleaf、Freemarker 等。 二、Spring Boot的主要特性 2.1、自动配置 开发者无需手动配置大量 XML 或注解,Spring Boot 能够根据项目中添加的依赖,自动为应用程序生成合理的默认配置,减少手动配置。例如,在项目中添加了 spring-boot-starter-web 依赖,Spring Boot 会自动配置嵌入式的 Tomcat 服务器,并为 Spring MVC 设置好必要的组件,如 DispatcherServlet 等,无需开发者手动编写大量的配置代码。 2.2、起步依赖(Starters) 起步依赖是指对常用库和框架的依赖声明的集合,使用起步依赖可以一次性地添加相关的依赖和配置到项目中,大大简化了项目的依赖管理,减少因依赖冲突而导致的问题。 比如,spring-boot-starter-data-jpa 包含了使用 Spring Data JPA 进行数据库操作所需的所有依赖,包括 Hibernate、Spring Data JPA 和数据库连接池等。 2.3、简化配置 Spring Boot 使用 application.properties 或 application.yml 作为统一的配置文件,将应用程序的各种配置集中管理,并且提供默认配置,尽量减少开发者的手动配置。这些配置文件放置在项目的类路径下,Spring Boot 会自动加载并应用其中的配置。 并且 Spring Boot 支持多环境配置,允许开发者根据不同的运行环境(如开发、测试、生产)使用不同的配置文件。通过在配置文件名中使用 {profile} 占位符,如 application-dev.yml、application-prod.yml,并在 application.yml 中指定 spring.profiles.active 属性来激活相应的环境配置。 2.4、内置服务器 Spring Boot 支持嵌入式的服务器,如 Tomcat、Jetty 和 Undertow 等,开发者可以将应用程序打包成一个可执行的 JAR 文件,使用 java -jar 命令可启动服务,无需单独部署到外部的应用服务器上。 例如,在开发 Web 应用时,只需在 pom.xml 文件中添加 spring-boot-starter-web 依赖,Spring Boot 会自动配置并启动一个嵌入式的 Tomcat 服务器,让开发者可以快速进行开发和测试。 2.5、无代码生成与 XML 配置 Spring Boot 无需代码生成和 XML 配置,完全基于注解和 Java 配置。 三、Spring Boot的配置 3.1、配置文件类型 Spring Boot 支持两种主要的配置文件类型:application.properties 和 application.yaml(.yml)。 3.1.1、application.properties 这是传统的 Java 配置文件格式,每行定义一个属性,采用 key=value 的形式。例如: server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/spring_db spring.datasource.username=root spring.datasource.password=password 3.1.2、application.yaml(或.yml) YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,它的特点包括: 使用缩进(空格数不限)表示层级关系(必须用空格缩进,不能使用 Tab) 使用 key: value 的形式表示键值对 支持列表、嵌套结构等复杂数据类型 例如: server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: password 关于 .yaml 和 .yml 的区别: 在 Spring Boot 项目中,YAML 文件通常以 .yaml 或 .yml 作为文件扩展名。 这两种扩展名本质上是相同的,它们都表示 YAML 格式的文件。.yaml 是 YAML 文件的官方推荐扩展名,而 .yml 是 .yaml 的简写形式。在功能上两者完全等价,Spring Boot 对它们的解析方式没有任何区别,无论使用 .yaml 还是 .yml,Spring Boot 都能正确加载和解析配置文件。 如果同时存在 application.yaml 和 application.yml,Spring Boot 会优先加载 application.yml。 3.2、配置优先级 3.2.1、配置文件位置的优先级 优先级最高的配置是命令行参数,通过命令行传递的这个参数将会覆盖原配置: java -jar app.jar --server.port=9999 不同位置配置文件的优先级分别为: 项目根目录下的 /config 子目录中的配置文件 项目根目录中的配置文件 类路径下的 /config 包中的配置文件 类路径根目录中的配置文件 3.2.2、配置文件格式的优先级 如果在同一个目录下同时存在 application.properties、application.yml、application.yaml 这几个文件,那么 Spring Boot 对配置文件的加载优先级为: application.properties > application.yml > application.yaml 3.3、读取配置文件的方式 假设在 YAML 配置文件中存在如下配置: server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/spring_db?useSSL=false&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver userInfo: name: 张三 age: 30 likes: - 游戏 - 健身 - 读书 3.3.1、使用@Value注解 @Value 注解可以直接将配置文件中的单个属性值注入到类的字段中。 @Component public class ConfiurationBean { // 简单属性 @Value("${spring.datasource.url}") private String url; // 数组 @Value("${userInfo.likes}") private String[] likes; // 数组里的其中一个属性 @Value("${userInfo.likes[1]}") private String like; // ... } 3.3.2、使用Environment对象 在 Spring Boot 中,Environment(org.springframework.core.env.Environment)是一个用于管理应用程序运行时环境配置信息的接口,它可以使开发者方便地获取和使用项目的配置参数,无论是来自 application.properties、application.yml 文件,还是系统环境变量、命令行参数等。 在需要使用 Environment 对象的类中,可以使用 @Autowired 注解将 Environment 对象自动注入进来,然后在类的方法中使用 getProperty() 方法获取配置信息。 @Component public class ConfiurationBean { @Autowired private Environment env; public void printProperty() { // 获取并使用属性 String port = env.getProperty("server.port"); System.out.println(port); } } 3.3.3、将部分配置封装成实体类 创建一个 Java 实体类,属性与配置项一一对应,使用 @ConfigurationProperties 注解将配置文件中的属性绑定到该 Java 对象上: @Component @ConfigurationProperties(prefix = "userInfo") public class UserInfo() { private String name; private int age; private String[] likes; // get方法、set方法、构造方法 } 3.4、多环境开发时配置文件的切换 在项目的开发中,常常需要在多个环境(开发环境 dev、生产环境 prod 等)部署项目,并且每个环境的配置可能都不太一样(如日志等级、数据库属性等),因此每个环境都有单独的一个配置文件。 Spring Boot 支持根据不同的环境加载不同的配置文件,常用的做法是建一个公共配置文件 application.properties 或 application.yml 来存放每个环境中相同的配置,再给每一个环境建一个单独的配置文件存放个性化配置,该配置文件的命名规则为 application-{profile}.properties 或 application-{profile}.yml。 例如开发环境的配置文件为 application-dev.yml,生产环境的配置文件为 application-prod.yml,则在公共配置文件 application.yml 中激活指定配置文件的方式为: spring: profiles: active: dev 也可以在启动项目 JAR 文件时通过命令行参数 spring.profiles.active 指定: java -jar app.jar --spring.profiles.active=dev 如果既在公共配置文件 application.yml/application.properties 中指定了激活哪个配置文件,又通过命令行参数指定,则最后生效的是命令行参数,因为命令行参数的优先级最高。 在 IDEA 中也可以直接指定命令行参数: 新版本 IDEA: 3.5、yml配置文件示例 server: port: 8081 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver # 数据源用druid type: com.alibaba.druid.pool.DruidDataSource # MyBatis配置 mybatis: # 指定Mapper XML文件的位置 mapper-locations: classpath:mapper/*.xml # 实体类的包路径 type-aliases-package: com.example.demos.web configuration: # 开启驼峰命名映射 map-underscore-to-camel-case: true # 项目日志等级 logging: level: # 全局日志等级 root: info # 设置MyBatis的日志级别为DEBUG com.example.mapper: debug org.mybatis: debug org.apache.ibatis: debug # 自定义配置 四、整合MyBatis 4.1、添加起步依赖 新版 IDEA 中可以直接在 pom.xml 文件的 <dependencies> 标签旁边点击 “Add Starters” 添加 MyBatis 与 MySql 的起步依赖: 或者手动在 pom.xml 文件中添加 MyBatis 的起步依赖与 MySQL、Druid 的依赖坐标: <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.22</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> 4.2、添加配置 然后在配置文件中添加数据源与 MyBatis 配置: spring: datasource: url: jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver # 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource # MyBatis配置 mybatis: # 指定Mapper XML文件的位置 mapper-locations: classpath:mapper/*.xml # 实体类的包路径 type-aliases-package: com.example.demos.web # 指定MyBatis的全局配置文件位置,可以进行更细颗粒度的MyBatis配置,不需要就不写 # config-location: classpath:mybatis-config.xml configuration: # 开启驼峰命名映射 map-underscore-to-camel-case: true # 项目日志等级 logging: level: # 全局日志等级 root: info # 设置MyBatis的日志级别为DEBUG com.example.mapper: debug org.mybatis: debug org.apache.ibatis: debug 4.3、扫描Mapper接口 最后在写接口的时候在上面用 @Mapper 注解标记一下这是 MyBatis 的 Mapper 接口: @Mapper public interface UserMapper { User select(); // ... } 或者直接在 Spring Boot 启动类上面用注解 @MapperScan() 进行全局配置扫描,指定 Mapper 接口类的包路径,Spring 会自动扫描该包下的所有接口,并将其注册为 MyBatis 的 Mapper 接口,无需在每个接口上都添加 @Mapper 注解。 @SpringBootApplication @MapperScan("com.example.mapper") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } 至此,Spring Boot 框架整合 MyBatis 框架完成。 五、使用Maven打包Spring Boot项目 在 pom.xml 文件中,确保配置了 Spring Boot Maven 插件: <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.6.3</version> <configuration> <!-- 指定启动程序主类 --> <mainClass>com.example.demo.DemoApplication</mainClass> <skip>false</skip> </configuration> </plugin> </plugins> </build> 在项目根目录下运行打包的命令: # 其实是两条命令,mvn clean是清除项目target目录下的文件,mvn package打包命令,两个命令一起执行。 # -Dmaven.test.skip=true表示排除测试代码之后打包 mvn clean package -Dmaven.test.skip=true 或者在 IDEA 中依次操作 clean 与 package: 打包时,一般都要先进行 clean 操作清理项目之前构建过程中生成的临时文件和输出文件,使项目恢复到初始状态,目的是确保项目不会受到之前构建结果的影响,避免旧的文件干扰新的构建过程。 打包完成后,会生成两个 JAR 文件,其中一个后缀为 .original,只包含工程中的 Class,不包含依赖;另一个后缀为 .jar 的文件是 SpringBoot 打包插件创建的,包含了应用依赖和 Spring Boot 相关的 Class,可以直接运行。生成的 JAR 文件保存在 target 目录下,文件名为 {项目名称}-{版本号}.jar。例如:demo-0.0.1-SNAPSHOT.jar 使用以下命令运行打包好的 JAR 文件: java -jar demo-0.0.1-SNAPSHOT.jar 并且可以通过命令来指定部分参数: java -jar demo-0.0.1-SNAPSHOT.jar --server.port=9999 --spring.profiles.active=prod
2021年12月20日
2,090 阅读
0 评论
2 点赞
2021-11-26
SpringMVC学习笔记
目录 一、SpringMVC介绍 二、映射请求路径 2.1、使用@ResquestMapping进行路径映射 2.2、@ResquestMapping的属性 2.2.1、value或path 2.2.2、method 2.2.3、params 2.2.4、headers 2.2.5、consumes 2.2.6、produces 2.3、@ResquestMapping的衍生注解 三、请求参数传递 3.1、GET/POST请求传递基础参数 3.2、传递复杂参数 3.2.1、日期类型 3.2.2、引用类型 3.2.3、数组 3.2.4、集合(List/Set/Map) 3.3、传递Json数据 四、响应 4.1、返回Json数据 4.2、封装返回结果 五、REST风格 5.1、简介 5.2、规则 5.3、相关注解 5.3.1、@RestController 5.3.2、@PathVariable 5.3.3、@RequestParam 5.3.4、@RequestBody 5.4、Rest风格开发示例 5.3.1、查询 5.3.2、新增 5.3.3、修改(更新) 5.3.4、删除 六、异常处理 6.1、自定义异常 6.2、处理异常的方式 6.2.1、使用@ControllerAdvice和@ExceptionHandler 6.2.2、实现HandlerExceptionResolver接口 七、拦截器 7.1、创建拦截器 7.2、注册和配置拦截器 7.3、执行流程和顺序 一、SpringMVC介绍 Spring MVC 是 Spring 框架中的一个模块,专门用于构建基于模型-视图-控制器(Model-View-Controller,MVC)设计模式的 Web 应用程序。 相关依赖坐标: <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.0.RELEASE</version> </dependency> 在 IDEA 中根据 “maven-archetype-webapp” 模板创建 Webapp 项目: 创建基本项目结构: 在 config 包里面新建初始化 Servlet 的配置类: public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } } 再新建 SpringMVC 配置类: @Configuration @ComponentScan("com.wlplove.controller") public class SpringMvcConfig { } 二、映射请求路径 2.1、使用@ResquestMapping进行路径映射 @RequestMapping 是 Spring MVC 中将 HTTP 请求映射到控制器方法的注解,它用于类级别或方法级别,可以根据请求的 URL、HTTP 请求方法(GET、POST 等)、请求参数、请求头等信息来匹配对应的处理逻辑。 @RequestMapping 注解应用在方法上,可以为该方法映射 URL 请求路径: public class UserController { @RequestMapping("/save") public String save() { // ... } } 也可以应用在类上,为该类中的所有方法设置基础的 URL 请求路径: @RequestMapping("/user") public class UserController { @RequestMapping("/save") public void save() { // ... } @RequestMapping("/delete") public void delete() { // ... } } 2.2、@ResquestMapping的属性 2.2.1、value或path 这两个属性作用相同,用于指定 URL 请求路径。用一个字符串映射一个路径,也可以用一个字符串数组映射多个路径。 @RequestMapping(value = "/save") @RequestMapping(path = "/save") // 映射多个路径 @RequestMapping(value = {"/save", "/saveUser"}) @RequestMapping(path = {"/save", "/saveUser"}) 一般也可以简写: @RequestMapping("/save") // 映射多个路径 @RequestMapping({"/save", "/saveUser"}) 2.2.2、method method 属性用于指定处理的 HTTP 方法。可以是一个 RequestMethod 枚举值或枚举值数组,常见的请求方法有 GET、POST、PUT、DELETE 等。 public class UserController { // save方法只处理POST和GET请求,路径为/save @RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String save() { // ... } } 2.2.3、params 用于指定请求中必须包含的请求参数和值。可以使用一些特殊的表达式,如 paramName 表示请求中必须包含 paramName 参数;!paramName 表示请求中不能包含 paramName 参数,paramName=value 表示请求中 paramName 参数的值必须为 value。 // 请求中必须包含name参数 @RequestMapping(value = "/save", params = "name") // 请求中不能包含name参数 @RequestMapping(value = "/save", params = "!name") // 请求中name参数的值必须是123 @RequestMapping(value = "/save", params = "name=123") // 请求中name参数的值不能是123 @RequestMapping(value = "/save", params = "name!=123") 2.2.4、headers 用于指定请求中必须包含的请求头及其值,用法与 params 类似。 // 只有当请求/download路径的Accept头的值为application/pdf时,downloadPdf方法才会被调用 @RequestMapping(value = "/download", headers = "Accept=application/pdf") @ResponseBody public String downloadPdf() { // ... } 2.2.5、consumes 用于指定请求的内容类型(Content-Type),即客户端发送给服务器的数据的格式。 // uploadJson方法只处理Content-Type为application/json的请求 @RequestMapping(value = "/upload", consumes = "application/json") @ResponseBody public String uploadJson() { // ... } 2.2.6、produces 用于指定响应的内容类型(Accept),即服务器返回给客户端的数据的格式。 // getHtml方法返回的响应内容类型为text/html @RequestMapping(value = "/get", produces = "text/html") @ResponseBody public String getHtml() { return "<html><body>Hello</body></html>"; } 2.3、@ResquestMapping的衍生注解 为了简化代码,Spring 还提供了一些 @RequestMapping 的衍生注解,它们实际上是 @RequestMapping(method = xxx) 的特定形式: @GetMapping:等同于 @RequestMapping(method = RequestMethod.GET),用于处理 HTTP Get 请求 @PostMapping:等同于 @RequestMapping(method = RequestMethod.POST),用于处理 HTTP Post 请求 @PutMapping:等同于 @RequestMapping(method = RequestMethod.PUT),用于处理 HTTP Put 请求 @DeleteMapping:等同于 @RequestMapping(method = RequestMethod.DELETE),用于处理 HTTP Delet 请求 @PatchMapping:等同于 @RequestMapping(method = RequestMethod.PATCH),用于处理 HTTP Patch 请求 三、请求参数传递 3.1、GET/POST请求传递基础参数 GET 请求的参数通过 URL 传递,附加在 URL 后面,形式为查询字符串(Query String),例如: http://localhost:8080/save?name=Jerry&age=13 POST 请求数据通过请求体(Request Body)传递,不会显示在 URL 中,在 Postman 中使用传递参数: 在 Java 的控制器方法中使用相同名称的形参,SpringMVC 可以自动将请求参数绑定到控制器方法中同名的形参上: @Controller public class UserController { // 如果要限制使用特定请求方法(POST/GET),将RequestMapping换成PostMapping或者GetMapping即可 @RequestMapping("/save") @ResponseBody public String save(String name, int age) { // ... } } 除此之外,SpringMVC 也支持将请求参数映射到不同名称的形参上,需要用 @RequestParam 注解指定请求参数绑定到控制器方法的哪个形参上: @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(@RequestParam("name")String userName, @RequestParam("age")int userAge) { // ... } } @RquestParam 注解的属性: value 或 name:指定请求参数的名称。如果省略,默认使用控制器方法的形参名作为参数名称。 required:指定参数是否为必填项。默认值为 true,表示请求中必须包含该参数,如果请求中缺少该参数,Spring 会抛出 MissingServletRequestParameterException。如果设置为 false,则参数可以为空。 defaultValue:指定参数的默认值。如果请求中未提供该参数,则使用该默认值。 3.2、传递复杂参数 3.2.1、日期类型 在请求中传递特定格式的日期: http://localhost:8080/save?date=2023-10-12 在控制层方法的形参前面加上 @DateTimeFormat 注解并指定日期格式,SpringMVC 就可以将同名请求参数转换为日期格式: @RequestMapping("/dateParse") @ResponseBody public String dateParse(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date) { // ... } 3.2.2、引用类型 例如存在一个 User 对象,其中包含一个引用类型的成员 address: public class Address { // 省 private String province; // 市 private String city; } public class User { // 姓名 private String name; // 年龄 private String age; // 地址——引用对象 private Address address; } 控制器方法中使用 User 对象接收参数: @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(User user) { // ... } } 那么在请求中传递参数时保持参数名与控制器方法形参名相同即可(不相同时使用 @RequestParam 绑定): GET: http://localhost:8080/save?name=Jerry&age=13&address.province=河南&address.city=开封 POST: 3.2.3、数组 控制器方法中使用数组接收参数: @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(String[] nameArray) { // ... } } 那么在请求中传递参数时都使用相同名称的参数即可: GET: http://localhost:8080/save?nameArray=Jerry&nameArray=Tom&nameArray=Mike POST: 3.2.4、集合(List/Set/Map) 控制器方法中使用集合接收参数(形参前需要加 @RequestParam 注解): @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(@RequestParam List<String> nameList) { // ... } } 在请求中传递参数的方式与数组相同: GET: http://localhost:8080/save?nameArray=Jerry&nameArray=Tom&nameArray=Mike POST: 3.3、传递Json数据 添加处理 Java 对象与 JSON 数据相互转换的依赖坐标: <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.2</version> </dependency> 在 SpringMVC 配置上添加 @EnableWebMvc 注解开启 Spring MVC 的默认配置(其中包括 Java 对象与 JSON 数据的相互转换): @Configuration @ComponentScan("com.wlplove.controller") @EnableWebMvc public class SpringMvcConfig { // ... } 发送的 JSON 数据: { "name": "Tom", "age": 12 } 控制器方法中用集合或者对象接收时形参前加上 @RequestBody 注解将请求体中的数据绑定到控制器方法的参数上: @RequestMapping("/json") @ResponseBody public String json2Dto(@RequestBody User user) { // ... } 四、响应 4.1、返回Json数据 需要添加 Jackson 的依赖: <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.2</version> </dependency> 在控制器方法上使用 @ResponseBody 注解,告知 SpringMVC 将控制层方法的返回值直接写进 HTTP 响应体,而不是解析为视图。最后 SpringMVC 通过 HttpMessageConverter 接口将返回值转换为适当的格式(如 JSON、XML等)。 @RequestMapping("/returnJson") @ResponseBody public User returnJson() { User user = new User(); user.setAge(20); user.setName("QWERT"); return user; } @ResponseBody 支持的返回值类型: 基本类型(String、int、boolean 等)。 自定义对象(User、Product 等)。 集合或数组(List<User>、String[] 等)。 4.2、封装返回结果 新建一个返回结果对象: public class Result { /** 状态码 */ private Integer code; /** 返回内容 */ private String msg; /** 数据对象 */ private Object data; public Result(Integer code, Object data) { this.code = code; this.data = data; } public Result(Integer code, String msg, Object data) { this.code = code; this.msg = msg; this.data = data; } // get和set方法 } 自定义返回编码: public class Code { public static final Integer OK = 000000; public static final Integer ERR =999999; // 其他编码 } 对 controller 方法的返回值都统一成这个返回对象: @Controller @RequestMapping("/users") public class UserController { @Autowired private UserMapper userMapper; @RequestMapping("/{id}") @ResponseBody public Result findById(@PathVariable Integer id) { User user = userMapper.selectById(id); Integer code = user != null ? Code.OK : Code.ERR; String msg = user != null ? "数据查询成功" : "数据查询失败"; return new Result(code, msg, user); } // ... } 五、REST风格 5.1、简介 REST(Representational State Transfer)风格是一种软件架构风格,用于设计网络应用程序,其核心概念旨在通过 HTTP 协议实现客户端与服务器之间简洁、可扩展且高效的交互。 传统风格资源描述形式: http://lcoalhost/user/getById?id=1 http://localhost/user/saveUser REST风格描述形式: http://localhost/user/1 http://localhost/user REST 风格是一种设计接口的约定方式,并非规范。 5.2、规则 REST 使用统一的接口与服务器进行交互,基于 HTTP 协议的标准方法: GET 用于获取资源 POST 用于创建资源 PUT 用于更新资源 DELETE 用于删除资源 5.3、相关注解 5.3.1、@RestController @RestController 是 Spring 4.0 引入的一个组合注解,它是 @Controller 和 @ResponseBody 的结合体。其主要作用是将一个控制器类标记为使用 REST 风格,使用 @RestController 注解的类中的所有处理方法默认都会将返回值直接写入 HTTP 响应体,以 JSON、XML 等数据格式返回,而不是返回视图进行渲染。 5.3.2、@PathVariable @PathVariable 是 Spring MVC 中用于将 URL 中的模板变量绑定到控制器方法形参上的注解。它通常用于 RESTful API 中,从 URL 路径中提取参数值。 如根据 ID 查询用户的控制器方法: @GetMapping("/users/{id}") public String findById(@PathVariable Long id) { // ... } 那么对于 GET 请求链接 http://localhost/users/123456,该控制器可以通过 @PathVariable 将 “123456” 绑定到形参 id 上。 也支持在路径中定义多个路径变量: http://localhost/users/123456/orders/987654321 在控制器方法中接收多个参数: @GetMapping("/users/{userId}/orders/{orderId}") public Order getOrder(@PathVariable Long userId, @PathVariable Long orderId) { // ... } Spring MVC 5.3 及以上版本支持可选路径变量。如果路径变量是可选的,可以设置属性 required = false: @GetMapping("/users/{id}") public User getUser(@PathVariable(required = false) Long id) { if (id == null) { // 返回所有用户 return userService.getAllUsers(); } // 返回指定id的用户 return userService.getUserById(id); } 那么: http://localhost/users id为null,返回所有用户 http://lcoalhost/users/123 返回id为123的用户 5.3.3、@RequestParam 详见 3.1。 5.3.4、@RequestBody 详见 3.3。 5.4、Rest风格开发示例 5.3.1、查询 // 查询全部 @GetMapping("/users") public xxxResponse findAll() { // ... } // 根据主键查询 @GetMapping("/users/{id}") public xxxResponse findById(@PathVariable Long id) { // ... } 5.3.2、新增 @PostMapping("/users") public xxxResponse add(@RequestBody User user) { // ... } 5.3.3、修改(更新) @PutMapping("/users") public xxxResponse update(@RequestBody User user) { //... } 5.3.4、删除 @DeleteMapping("/delete/{id}") public xxxResponse delete(@PathVariable Long id) { // ... } 六、异常处理 6.1、自定义异常 新建一个自定义异常类 BusinessException: public class BusinessException extends RuntimeException { private Integer code; public BusinessException(Integer code, String message) { super(message); this.code = code; } // get和set方法 } 自定义异常编码: public class ErrorCode { public static final Integer TIMEOUT_ERROR = 10001; // 其他异常编码 } 在业务层代码中抛出异常: throw new BusinessException(ErrorCode.TIMEOUT_ERROR, "请求超时,请稍后再试"); 6.2、处理异常的方式 6.2.1、使用@ControllerAdvice和@ExceptionHandler @ControllerAdvice 是 Spring 框架提供的一个用于定义全局异常处理、数据绑定和数据预处理等逻辑的注解。在配合标注了 @ExceptionHandler 注解的方法使用时,可以在拦截到对应的异常之后终止原 controller 方法的执行,并转入该方法执行设定好的异常处理逻辑。 在 controller 包中新建一个全局异常处理类 GlobalExceptionHandler,在类中的方法上面使用 @ExceptionHandler 注解指定这个方法要处理哪种异常: @ControllerAdvice public class GlobalExceptionHandler { // Exception是所有异常的父类,在此表示拦截到所有的异常都会进行处理 @ExceptionHandler(Exception.class) // 方法参数中加入这种异常类型的形参,就可以获取到这个异常的信息 public ResponseEntity<String> doException(Exception ex) { return new ResponseEntity<>("异常信息: " + ex.getMessage()); } // 只处理RuntimeException异常 @ExceptionHandler(RuntimeException.class) public Response<T> doRuntimeException(RuntimeException ex){ // RuntimeException异常处理逻辑 } // 只处理IOException异常 @ExceptionHandler(IOException.class) public Response<T> doIOException(IOException ex){ // IOException异常处理逻辑 } // ... } 如果在控制器中使用 Rest 风格的开发,可以使用 @RestControllerAdvice 注解,@RestControllerAdvice 是 @ControllerAdvice 和 @ResponseBody 的组合注解,类中的方法返回值会自动进行 JSON 或 XML 等格式的序列化,直接作为响应体返回给客户端。 6.2.2、实现HandlerExceptionResolver接口 HandlerExceptionResolver 是 Spring Web 框架中的一个接口,它提供了一种统一处理控制器(@Controller)中抛出的异常的机制。通过实现这个接口,开发者可以自定义异常处理逻辑,以满足不同的业务需求,比如返回特定格式的错误响应、记录异常日志等。 处理异常主要通过该接口中的 resolveException 方法实现 方法参数: HttpServletRequest request:当前请求对象,通过它可以获取请求的各种信息,如请求头、请求参数等。 HttpServletResponse response:当前响应对象,可用于设置响应头、响应状态码等。 Object handler:处理当前请求的处理器对象,通常是一个控制器方法。 Exception ex:在处理请求过程中抛出的异常对象。 方法返回值: ModelAndView 是 Spring MVC 中用于封装视图和模型数据的类。如果返回 null,表示该异常解析器没有处理该异常,Spring 将继续尝试其他的异常解析器。如果返回一个非空的 ModelAndView 对象,Spring 会根据其中的视图信息渲染相应的视图,并将模型数据传递给视图。 新建一个异常处理类 CustomExceptionResolver,用 @Component 注解声明这是一个 Spring Bean,实现 HandlerExceptionResolver 接口中的 resolveException 方法: @Component public class CustomExceptionResolver implements HandlerExceptionResolver { public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView modelAndView = new ModelAndView(); if (ex instanceof IllegalArgumentException) { modelAndView.setViewName("error/400"); // 跳转到 400 错误页面 modelAndView.addObject("errorMessage", "非法参数: " + ex.getMessage()); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); } else { modelAndView.setViewName("error/500"); // 跳转到 500 错误页面 modelAndView.addObject("errorMessage", "服务器内部错误: " + ex.getMessage()); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } return modelAndView; } } 七、拦截器 在 Spring 中,拦截器是利用 AOP(面向切面编程)的思想实现的一种机制,用在请求处理的不同阶段(如请求到达 controller 方法之前、controller 方法执行之后、视图渲染之前等)执行自定义逻辑,在以下的场景中广泛使用: 权限验证:在请求到达控制器之前,检查用户是否具有访问该资源的权限,如验证用户登录状态。 日志记录:记录请求的相关信息,如请求的 URL、参数、处理时间等,方便后续的调试和监控。 性能监控:统计请求的处理时间,找出性能瓶颈。 请求参数处理:对请求参数进行统一的预处理,如编码转换、参数验证等。 7.1、创建拦截器 在 controller 包中新建一个包 interceptor,创建拦截器类 ProjectInterceptor,实现 HandlerInterceptor 接口,并用 @Component 声明为一个 bean: @Component public class ProjectInterceptor implements HandlerInterceptor { // 在控制器处理请求之前调用 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 通过handler对象经过反射可以获取到原controller方法 System.out.println("preHandle: 请求到达控制器之前"); // 可以在此处进行权限验证、日志记录等操作 // 如果返回 false,请求将被中断,不再执行postHandle与afterCompletion return true; } // 在控制器处理请求之后、视图渲染之前调用 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle: 控制器处理请求之后"); // 可以在此处修改模型数据或视图 } // 在视图渲染完成之后调用(无论请求是否成功) @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion: 视图渲染完成之后"); // 可以在此处进行资源清理、日志记录等操作 } } 7.2、注册和配置拦截器 在 config 包下新建一个配置类 SpringMvcSupport,继承 WebMvcConfigurationSupport 类,并重写 addInterceptors 方法,在这个方法中注册和配置拦截器: @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { // 注入之前定义好的拦截器类 @Autowired private ProjectInterceptor projectInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor) // 指定要拦截的路径,可以传入多个路径 .addPathPatterns("/**") // 指定要排除的路径,可以传入多个路径 .excludePathPatterns("/login", "/register"); } } addPathPatterns 和 excludePathPatterns 方法均支持 Ant 风格的路径匹配规则,具体语法规则如下: ?:匹配单个字符。 示例:/user? 可以匹配 /user1、/userA,但不能匹配 /user12。 \*:匹配任意数量的字符(不包括路径分隔符 /)。 示例:/user/* 可以匹配 /user/123、/user/profile,但不能匹配 /user/123/address。 `\**:匹配任意数量的字符(包括路径分隔符/`)。 示例:/user/** 可以匹配 /user/123、/user/123/address。 {variable}:匹配路径变量。 示例:/user/{id} 可以匹配 /user/123,并将 123 绑定到路径变量 id 除了新建一个 SpringMvcSupport 配置类来配置拦截器的方法外,还可以让原来的 SpringMvc 配置类来实现 WebMvcConfigurer 接口中的 addInterceptors 方法,也能达到相同的效果: @Configuration @ComponentScan("com.xxx.controller") @EnableWebMvc public class SpringMvcSupport implements WebMvcConfigurer { // 注入之前定义好的拦截器类 @Autowired private ProjectInterceptor projectInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor) // 指定要拦截的路径,可以传入多个路径 .addPathPatterns("/**") // 指定要排除的路径,可以传入多个路径 .excludePathPatterns("/login", "/register"); } } 7.3、执行流程和顺序 拦截器执行流程: 如果有多个拦截器,形成拦截器链,它们的执行顺序如下: preHandle:按照注册顺序依次执行,必定运行。 postHandle:按照注册顺序的逆序执行,可能不运行。 afterCompletion:按照注册顺序的逆序执行,可能不运行。 例如拦截器 A、B、C 按顺序注册: preHandle 执行顺序:A → B。 postHandle 执行顺序:B → A。 afterCompletion 执行顺序:B → A。
2021年11月26日
2,226 阅读
0 评论
3 点赞
2021-11-13
Spring学习笔记(四) - SSM框架整合
目录 一、创建Webapp项目 二、Spring配置类 三、数据源对象(以Druid为例) 四、整合MyBatis 4.1、数据库配置 4.2、MyBatis配置 五、整合SpringMVC 六、整合Log4j 七、整合Junit 环境说明: 数据库:MySQL 8.0 Java版本:JDK8 通过注解整合 SSM 框架流程: 创建 Web 工程 SSM 整合 Spring 框架:SpringConfig MyBatis 框架:JdbcConfig / jdbc.properties / MybatisConfig SpringMVC 框架:ServletConfig / SpringMvcConfig 一、创建Webapp项目 在 IDEA 中根据 “maven-archetype-webapp” 模板创建 Webapp 项目: 创建基本项目结构: 二、Spring配置类 引入 spring-conext 的依赖坐标: <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.25.RELEASE</version> </dependency> 创建一个 Java 类 SpringConfig 作为 Spring 配置类,类上面添加 @Configuration 注解标识这是一个配置类,添加 @ComponentScan 注解来设置扫描注解的路径 @Configuration @ComponentScan("com.xxx") /** * 如果有多个要扫描的包路径,可以用数组格式: * @ComponentScan({"com.xxx.dao","com.xxx.service"}) */ public class SpringConfig { } 三、数据源对象(以Druid为例) 导入 Druid 数据源的依赖坐标: <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.22</version> </dependency> 新建一个配置数据库连接信息的类 JdbcConfig,里面引入配置文件中的数据库信息,然后用一个方法构造并返回一个 DataSource 对象,最后用 @Bean 注解设置这个方法的返回值成为 Spring IoC 容器的一个 Bean: public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 数据源Bean * @return */ @Bean public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); return ds; } } Spring 配置类 SpringConfig 中用 Import 注解引入 JdbcConfig 这个类: @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class}) public class SpringConfig { } 四、整合MyBatis 4.1、数据库配置 在 src/main/resources 目录下新建一个配置数据库连接信息的配置文件 jdbc.properties: jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=root 使用 @PropertySource 注解在 Spring 配置类 SpringConfig 上加载外部的 properties 文件: @Configuration @ComponentScan({"com.xxx"}) +@PropertySource("classpath:jdbc.properties") public class SpringConfig { } 4.2、MyBatis配置 导入 MyBatis 及 MySQL 的相关依赖坐标: <!-- spring-jdbc --> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.25.RELEASE</version> </dependency> <!-- mybatis --> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.16</version> </dependency> <!-- mybatis-spring --> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <!-- mysql --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> 新建一个 MyBatis 的配置类 MybatisConfig,配置 SqlSessionFactoryBean 和 MapperScannerConfigurer 这两个 Bean: public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setDataSource(dataSource); ssfb.setTypeAliasesPackage("com.xxx.xxx"); return ssfb; } @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer msc = new MapperScannerConfigurer(); // Mapper的XML映射文件所在路径 msc.setBasePackage("com.xxx.dao"); return msc; } } Spring 配置类 SpringConfig 中用 Import 注解引入 MybatisConfig 这个类: @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class, MybatisConfig.class}) @PropertySource("classpath:jdbc.properties") public class SpringConfig { } 五、整合SpringMVC 导入 SpringMVC、Servlet 与 jackson 的依赖坐标: <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.25.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.2</version> </dependency> 新建 SpringMVC 配置类 SpringMvcConfig: @Configuration @ComponentScan("com.wlplove.controller") @EnableWebMvc public class SpringMvcConfig { } 新建 Servlet 的初始化类 ServletInitializer: public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } } 六、整合Log4j 导入 Log4j 的依赖坐标: <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.23.1</version> </dependency> 在 "src/main/java/resources" 下新建一个 Log4j 的配置文件 Log4j2.xml: <?xml version="1.0" encoding="UTF-8"?> <!-- Configuration 具有 Appenders 和 Loggers 这两种子节点,每个子节点可以定义多个 --> <configuration> <!-- Appender节点,具有 Console(控制台)、File(文件)、RoolingFile(滚动文件)这三种类型的子节点 --> <Appenders> <!-- 输出日志信息到控制台 --> <Console name="console" target="SYSTEM_OUT"> <!--指定控制日志输出的格式--> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> </Console> <!-- File 节点用来定义输出到指定位置的文件的 Appender,会将所有内容写入到同一个文件中 --> <!-- append属性设置写入新的日志时是追加在原内容后面,还是清除所有内容之后再写入 --> <!-- <File name="allLog" fileName="logs/AlliInOne.log" append="true">--> <!-- <ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>--> <!-- <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{9.9.9.1}(%L) %m%n"/>--> <!-- </File>--> <!-- RollingFile 节点,将日志写入文件,但是允许日志文件根据时间或大小进行滚动,从而避免单个文件过大 --> <!-- fileName 生成的初始日志文件 --> <RollingFile name="rollingFileInfo" fileName="logs/${date:yyyy-MM}/log-info-${date:yyyy-MM-dd}.log" filePattern="logs/${date:yyyy-MM}/log-info-%d{yyyy-MM-dd}-%i.log"> <!-- ThresholdFilter 只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --> <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <!-- PatternLayout 指定控制日志输出的格式,不设置默认为:%m%n --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> <!-- Policies 滚动策略 --> <Policies> <!-- 按时间滚动 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 按大小滚动 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- DefaultRolloverStrategy 设置一个文件下保存的日志文件数量,不设置则默认为同一文件夹下7个文件,超过这个数量后,最老的文件将被删除 --> <DefaultRolloverStrategy max="20"/> </RollingFile> </Appenders> <!-- 在 Loggers 中引入上面定义好的 Appender --> <loggers> <!-- level指定日志级别,从低到高的优先级: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <!-- 设置org.mybatis包下的日志只打印WARN及以上级别 --> <Logger name="org.mybatis" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <!-- 设置org.springframework包下的日志只打印WARN及以上级别 --> <Logger name="org.springframework" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <root level="DEBUG"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </root> </loggers> </configuration> Log4j 配置文件详解:彻底掌握Log4j2 - 蚂蚁小哥 - 博客园 修改 MyBatis 配置类中的 SqlSessionFactoryBean,设置其 Configuration 属性: public class MybatisConfig { // ... @Bean public SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.xxx.xxx"); ssfb.setDataSource(dataSource); + Configuration configuration = new Configuration(); + // 修改MyBatis使用的日志框架为Log4j + configuration.setLogImpl(Log4j2Impl.class); + ssfb.setConfiguration(configuration); return ssfb; } // ... } 七、整合Junit 导入 Junit 和 Spring-test 的依赖坐标: <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> 新建一个测试类: // 在 JUnit 5 中集成 Spring 功能(如果是Junit4则换成@RunWith(SpringJunit4ClassRunner.class)) @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = SpringConfig.class) public class SpringTest { @Autowired private UserMapper userMapper; @Test public void find() { User user = userMapper.select(); } }
2021年11月13日
1,548 阅读
0 评论
1 点赞
2021-11-10
Spring学习笔记(三) - 注解
目录: 一、通过注解定义Bean 1.1、启用注解支持 1.2、定义Bean 1.3、@Component的派生注解 1.3.1、@Repository 1.3.2、@Service 1.3.3、@Controller 1.3.4、@Configuration 1.4、用注解代替XML配置文件 1.4.1、配置类 1.4.2、初始化IoC容器 二、通过注解使用Bean 2.1、自动装配 2.1.1、@Autowired 2.1.2、@Qualifier 2.1.3、@Resource 2.1.4、@Primary 2.1.5、@Value 2.2、读取properties文件配置 2.3、作用域 2.4、自定义Bean初始化/销毁操作 2.5、总结 三、整合框架 3.1、数据源对象(以Druid为例) 3.2、整合Mybatis 3.3、整合Log4j 3.4、整合Junit 四、Spring事务 一、通过注解定义Bean 1.1、启用注解支持 <context:annotation-config /> 若要以注解方式注入 Bean,则需要开启扫描包中的组件,并用 base-package 属性指定扫描的基本包路径: <context:component-scan base-package="com.xxx" /> 使用 <context:annotation-scan> 标签时,默认将隐式启用对注解的支持。 1.2、定义Bean 在 XML 配置中如果要将一个 Bean 交给 Spring IoC 容器管理,需要进行如下配置: <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl" /> 若用注解要实现相同目的,只需要在要被管理的 Java 类上添加 @Component 注解,并在后面的括号中指定 Bean 的名称: // 注解后面的括号里是 bean 的名称 @Component("userServiceImpl") public class UserServiceImpl implements UserService { // ... } @Component 注解也可以不指定 Bean 名称,Spring 会自动为该 Bean 生成一个默认的名称,通常是类名的首字母小写形式: @Component // 可以用名称“userServiceImpl”来获取这个Bean public class UserServiceImpl implements UserService { // ... } 所以只需要在 Java 类上加入 @Component 注解,用于标识这个类是 Spring 容器中的组件(即 Bean),就可以实现与 XML 配置中的 <bean> 标签相同的作用。 1.3、@Component的派生注解 此外,Spring 还提供了 @Component 的几个派生注解:@Repository、@Service、@Controller、@Configuration,这几个注解的功能和用法与 @Component 相同,但它们在使用场景上有所不同。 1.3.1、@Repository 用于数据访问层(Dao 层)中与数据库交互的类。 Spring 会对使用 @Repository 注解的类进行特定的异常处理(将数据访问层的异常,如 SQLException 等转换为 Spring 的 DataAccessException 异常,方便统一处理和异常传播)。 @Repository public interface UserMapper { // ... } 1.3.2、@Service 用于标识业务逻辑层(Service 层)中处理核心业务逻辑的类。 使用 @Service 注解可以将一个类声明为业务逻辑组件,将其对象存入 Spring 容器中,以便在其他组件(如Controller)中通过注入该 service 类的实例来使用其业务逻辑。 @Service public class UserServiceImpl implements UserService { // ... } 1.3.3、@Controller 用于标识控制层(Controller 层)中处理响应和请求的类。 被 @Controller 标记的类实际上就是一个 Spring MVC Controller 对象,它可以处理请求,并通过 @RequestMapping 等注解将不同的请求分发到对应的方法上。 @Controller public class UserController { // ... } 1.3.4、@Configuration 用于标记替换 XML 配置文件的配置类,这个注解的用法将在 1.4 中详细说明。 1.4、用注解代替XML配置文件 Spring 支持完全去除 XML 配置文件实现纯注解开发,实现的方式就是使用一个 Java 类来代替原本的 XML 配置文件。 1.4.1、配置类 创建一个 Java 类,类上面添加 @Configuration 注解标识这是一个配置类: @Configuration public class SpringConfig { // ... } 在 XML 配置文件中会用到 <context:annotation-config base-package=""> 标签来设置扫描注解的路径,在配置类上添加 @ComponentScan 注解也可以实现相同的效果: @Configuration +@ComponentScan("com.xxx") public class SpringConfig { // ... } 如果有多个包路径,可以用数组格式: @ComponentScan({"com.xxx.dao","com.xxx.service"}) 1.4.2、初始化IoC容器 当创建出一个配置类之后,初始化 Spring IoC 容器的方式也需要改变。 原来是通过 ClassPathXmlApplicationContext 类加载 XML 配置文件初始化得到 IoC 容器: ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml"); 现在改用 AnnotationConfigApplicationContext 类来加载配置类得到 Spring IoC 容器: ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); 二、通过注解使用Bean 2.1、自动装配 2.1.1、@Autowired 在要引用的依赖上面使用 @Autowired 注解开启自动装配注入该依赖: @Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.insert(); } } @Autowired 注解默认按照类型(byType)进行自动装配。 2.1.2、@Qualifier 如果 Spring IoC 容器中存在多个类型相同的 Bean 时,仅仅使用 @Autowired 根据类型自动装配时就导致 Spring 无法确定应该自动注入哪一个 Bean,便会抛出 NoUniqueBeanDefinitionException 异常。那么此时使用 @Qualifier 注解来指定要装配的 Bean 名称: @Repository public class BookDao1 implements BookDao { // ... } @Repository public class BookDao2 implements BookDao { // ... } @Service public class BookServiceImpl implements BookService { @Autowired // 存在两个BookDao类型的Bean,这里指定注入名称为bookDao1的Bean @Qualifier("bookDao1") private BookDao bookDao; } 需要注意的是,@Qualifier 不能单独使用,必须与 @Autowired 一起使用。因为 @Autowired 主要是根据类型进行自动装配,而 @Qualifier 则在此基础上匹配 Bean 名称,从而进行更精确的限制。 2.1.3、@Resource 还有一个与 @Autowired 类似的注解是 @Resource,默认按照名称(byName)进行自动装配,通过其 name 属性指定要注入的 Bean 名称: @Service public class BookServiceImpl implements BookService @Resource(name = "bookDao2") private BookDao bookDao; } 不像 @Autowired 是 Spring 框架提供的用于按类型(byType)自动装配的注解,@Resource 是 JavaEE 标准中(javax.annotation.Resource)提供的用于按名称(byName)自动装配的注解,并非 Spring 框架所特有的。 2.1.4、@Primary 与 @Qualifier 类似,@Primary 注解也可以用来解决当存在多个相同类型的 Bean 时应该注入哪一个 Bean 的问题。 如果 Spring IoC 容器中存在多个类型相同的 Bean,给该 Bean 上面添加 @Primary 注解,则 Spring 会优先使用标注了 @Primary 的 Bean。 2.1.5、@Value 使用 @Value 注解实现简单类型的注入: @Service public class UserServiceImpl implements UserService { @Value(30) private int age; @Value("root") private String userName; } @Value 注解除了用于给简单类型的成员注入固定的值以外,也可以用于将配置文件中的属性注入给简单类型的成员,配置文件中的属性名写在占位符 ${} 里面: @Service public class UserServiceImpl implements UserService { @Value("${user.name}") private String userName; } 2.2、读取properties文件配置 在 src/main/resources 目录下新建一个配置数据库连接信息的配置文件 jdbc.properties: jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=root 使用 @PropertySource 注解在 Spring 配置类上加载外部的 properties 文件,在要注入值的成员上添加 @Value 注解指定注入哪个属性: /** * Spring配置类 */ @Configuration @ComponentScan({"com.xxx"}) @PropertySource("classpath:jdbc.properties") public class SpringConfig { // ... } /** * 使用属性 */ public class DataBaseConnInfo { // 注入配置文件中的属性 @Value("${jdbc.driverName}") private String driverName; @Value("${jdbc.url}") private String url; } 若要加载多个配置文件应使用数组: @PropertySource({"classpath:jdbc.properties","classpath:appConfig.properties"}) 2.3、作用域 使用注解 @Scope 定义 Bean 的作用域是 prototype(原型/非单例)或者 singleton(单例)。 public class AppConfig { @Bean // @Scope("prototype") @Scope("singleton") public MyBean myBean() { return new MyBean(); } } 2.4、自定义Bean初始化/销毁操作 使用 @PostConstruct 注解定义初始化方法(方法名不限),将在构造方法之后执行该方法。 使用 @PreDestroy 注解定义销毁方法(方法名不限),在容器销毁前执行该方法,一般用来释放占用的资源等。 public class UserServiceImpl implements UserService { @PostConstruct publid void init() { System.out.println("init ...."); } @PreDestroy public void destory() { System.out.println("destory ..."); } } 2.5、总结 三、整合框架 3.1、数据源对象(以Druid为例) 导入 Druid 数据源的依赖坐标: <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.22</version> </dependency> 新建一个配置数据库连接的类 JdbcConfig,里面引入配置文件中的数据库信息,然后用一个方法构造并返回一个 DataSource 对象,最后用 @Bean 注解设置这个方法的返回值成为 Spring IoC 容器的一个对象: public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 数据源 * @return */ @Bean public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); return ds; } } Spring 配置类中用 Import 注解引入 JdbcConfig 这个类: @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class}) public class SpringConfig { // ... } 3.2、整合Mybatis 导入 MyBatis 的依赖坐标: <!-- spring-jdbc --> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>6.1.4</version> </dependency> <!-- mybatis --> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.16</version> </dependency> <!-- mybatis-spring --> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <!-- mysql --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> 新建一个 MyBatis 配置类 MybatisConfig,配置 SqlSessionFactoryBean 和 MapperScannerConfigurer 这两个 Bean: public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setDataSource(dataSource); ssfb.setTypeAliasesPackage("com.xxx.xxx"); return ssfb; } @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer msc = new MapperScannerConfigurer(); // Mapper接口所在的包路径 msc.setBasePackage("com.xxx.mapper"); return msc; } } Spring 配置类中用 Import 注解引入 MybatisConfig 这个类: @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class, MybatisConfig.class}) public class SpringConfig { // ... } 3.3、整合Log4j 导入 Log4j 的依赖坐标: <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.23.1</version> </dependency> 在 "src/main/java/resources" 下新建一个 Log4j 的配置文件 Log4j2.xml: <?xml version="1.0" encoding="UTF-8"?> <!-- Configuration 具有 Appenders 和 Loggers 这两种子节点,每个子节点可以定义多个 --> <configuration> <!-- Appender节点,具有 Console(控制台)、File(文件)、RoolingFile(滚动文件)这三种类型的子节点 --> <Appenders> <!-- 输出日志信息到控制台 --> <Console name="console" target="SYSTEM_OUT"> <!--指定控制日志输出的格式--> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> </Console> <!-- File 节点用来定义输出到指定位置的文件的 Appender,会将所有内容写入到同一个文件中 --> <!-- append属性设置写入新的日志时是追加在原内容后面,还是清除所有内容之后再写入 --> <!-- <File name="allLog" fileName="logs/AlliInOne.log" append="true">--> <!-- <ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>--> <!-- <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{9.9.9.1}(%L) %m%n"/>--> <!-- </File>--> <!-- RollingFile 节点,将日志写入文件,但是允许日志文件根据时间或大小进行滚动,从而避免单个文件过大 --> <!-- fileName 生成的初始日志文件 --> <RollingFile name="rollingFileInfo" fileName="logs/${date:yyyy-MM}/log-info-${date:yyyy-MM-dd}.log" filePattern="logs/${date:yyyy-MM}/log-info-%d{yyyy-MM-dd}-%i.log"> <!-- ThresholdFilter 只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --> <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <!-- PatternLayout 指定控制日志输出的格式,不设置默认为:%m%n --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> <!-- Policies 滚动策略 --> <Policies> <!-- 按时间滚动 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 按大小滚动 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- DefaultRolloverStrategy 设置一个文件下保存的日志文件数量,不设置则默认为同一文件夹下7个文件,超过这个数量后,最老的文件将被删除 --> <DefaultRolloverStrategy max="20"/> </RollingFile> </Appenders> <!-- 在 Loggers 中引入上面定义好的 Appender --> <loggers> <!-- level指定日志级别,从低到高的优先级: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <!-- 设置org.mybatis包下的日志只打印WARN及以上级别 --> <Logger name="org.mybatis" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <!-- 设置org.springframework包下的日志只打印WARN及以上级别 --> <Logger name="org.springframework" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <root level="DEBUG"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </root> </loggers> </configuration> Log4j 配置文件详解:彻底掌握Log4j2 - 蚂蚁小哥 - 博客园 修改 Mybatis 配置类中的 SqlSessionFactoryBean,设置其 Configuration 属性: public class MybatisConfig { // ... @Bean public SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.xxx.xxx"); ssfb.setDataSource(dataSource); + Configuration configuration = new Configuration(); + // 修改MyBatis使用的日志框架为Log4j2 + configuration.setLogImpl(Log4j2Impl.class); + ssfb.setConfiguration(configuration); return ssfb; } // ... } 3.4、整合Junit 导入 Junit 和 spring-test 的依赖坐标: <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> 新建一个测试类: // 在 JUnit 5 中集成 Spring 功能,如果是Junit4则换成@RunWith(SpringJunit4ClassRunner.class) @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = SpringConfig.class) public class SpringTest { @Autowired private UserMapper userMapper; @Test public void find() { User user = userMapper.select(); } } 四、Spring事务 导入 Spring 事务的依赖坐标: <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.10.RELEASE</version> </dependency> 在 Spring 的配置类上添加注解 @EnableTransactionManagement 开启 Spring 的事务管理功能: @Configuration @ComponentScan("com.xxx") @Import({JdbcConfig.class, MybatisConfig.class}) +@EnableTransactionManagement public class SpringConfig { // ... } 配置类中添加 PlatformTransactionManager 这个 Bean: @Bean public PlatformTransactionManager getTransactionManager(DataSource dataSource) { DataSourceTransactionManager dstm = new DataSourceTransactionManager(); dstm.setDataSource(dataSource); return dstm; } 最后在 service 方法或类上面用 @Transactional 注解设置添加事务管理,在执行该方法或类中的方法时便会开启事务管理,如果程序执行时发生异常就回滚之前的数据库操作。 需要注意的是,当在同一类中调用有 @Transactional 注解的方法时,可能不会触发事务管理,因为它绕过了 Spring 的代理机制,解决办法是将这个方法也标记为 @Transactional。
2021年11月10日
625 阅读
0 评论
1 点赞
2021-11-07
Spring学习笔记(二) - 通过XML配置整合框架
目录: 一、创建Webapp项目 二、加载properties文件 2.1、新建properties文件 2.2、指定要加载的properties文件 2.3、读取properties文件属性值的方式 三、数据源对象(以Druid为例) 3.1、导入Druid数据源依赖坐标 3.2、在XML文件中配置数据源对象为Spring管理的Bean 四、整合MyBatis 4.1、导入依赖坐标 4.2、配置SqlSessionFactoryBean 4.3、配置MapperScannerConfigurer 五、整合Junit 六、整合Log4j 在 pom.xml 文件中导入 Spring 的坐标依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> 一、创建Webapp项目 在 IDEA 中根据 “maven-archetype-webapp” 模板创建 Webapp 项目: 创建基本项目结构: 在 src/main/resources 目录下新建一个 spring-config.xml 文件作为 Spring 的配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Spring配置内容 --> </beans> 二、加载properties文件 2.1、新建properties文件 在 src/main/resources 目录下新建一个配置数据库连接信息的配置文件 jdbc.properties: jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db jdbc.username=root jdbc.password=root 2.2、指定要加载的properties文件 在 Spring 的 XML 配置文件中加载指定 properties 文件,写法有多种: 加载资源路径(src/main/java/resources)下指定的一个 properties 文件: <context:property-placeholder location="classpath:jdbc.properties"/> 也可以加载资源路径下的多个 properties 文件: <context:property-placeholder location="classpath:jdbc.properties,classpath:jdbc2.properties"/> 使用通配符加载 properties 文件:在资源路径或 jar 包中搜索并加载所有 properties 文件 <context:property-placeholder location="classpath*:*.properties"/> 再加上 system-properties-mode="NEVER",表示 Spring 容器在解析 properties 配置文件时,不使用系统属性来替换配置文件中的属性,从而避免系统属性对配置产生影响: <context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/> 2.3、读取properties文件属性值的方式 <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> 三、数据源对象(以Druid为例) 3.1、导入Druid数据源依赖坐标 <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.22</version> </dependency> 3.2、在XML文件中配置数据源对象为Spring管理的Bean <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <!-- 使用属性占位符 ${} 读取 properties 文件中的属性 --> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- 初始连接数 --> <property name="initialSize" value="10"/> <!-- 最大连接池数量 --> <property name="maxActive" value="100"/> <!-- 超时时间 设置为-1时,如果没有可用连接,连接池会一直无限期等待,直到获取到连接为止。 如果设置为N(毫秒),则连接池会等待N毫秒,等待不到,则抛出异常 --> <property name="maxWait" value="-1"/> </bean> 四、整合MyBatis 4.1、导入依赖坐标 <!-- spring-jdbc --> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>6.1.4</version> </dependency> <!-- mybatis --> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.16</version> </dependency> <!-- mybatis-spring --> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <!-- mysql --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> 4.2、配置SqlSessionFactoryBean SqlSessionFactoryBean 是 Spring 与 MyBatis 集成时使用的一个关键类,它实现了 Spring 的 FactoryBean<SqlSessionFactory> 接口,用于创建 SqlSessionFactory 对象。 <!-- 配置 SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入数据源,dataSource是在前面配置的数据库连接池 --> <property name="dataSource" ref="dataSource"/> <!-- 从类路径下加载在mybatis/mappers包和它的子包中所有的MyBatis映射器XML文件 --> <property name="mapperLocations" value="classpath*:com/wlplove/dao/*.xml"/> <!-- 为Java类型设置简短的名称,从而在MyBatis的映射器文件中直接使用这个名称,而不需要写完整的类名 --> <property name="typeAliasesPackage" value="com.wlplove.domain"/> <!-- 通过configLocation属性指定mybatis配置文件路径,不加入这个属性则使用Spring中的配置 --> <!-- <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>--> <!--MyBbatis配置 --> <property name="configuration"> <bean class="org.apache.ibatis.session.Configuration"> <property name="mapUnderscoreToCamelCase" value="true"/> <property name="cacheEna bled" value="true"/> <property name="defaultExecutorType" value="SIMPLE"/> <!-- 指定MyBatis所用日志的具体实现 --> <property name="logImpl" value="org.apache.ibatis.logging.log4j2.Log4j2Impl"/> </bean> </property> </bean> 4.3、配置MapperScannerConfigurer MapperScannerConfigurer 是 Spring 框架中用于整合 MyBatis 的一个配置类,它可以扫描指定包下的 Mapper 接口,并将它们的实现类自动注入到 Spring IoC 容器中。 <bean name="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- basePackage属性指定自动扫描Mapper接口所在的包 --> <property name="basePackage" value="com.wlplove.dao"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> 五、整合Junit 导入 Junit 和 spring-test 的依赖坐标: <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> 新建一个测试类: // 在 JUnit 5 中集成 Spring 功能,如果是Junit4则换成@RunWith(SpringJunit4ClassRunner.class) @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = SpringConfig.class) public class SpringTest { @Autowired private UserMapper userMapper; @Test public void test() { User user = userMapper.select(); } } 六、整合Log4j 导入 Log4j 的依赖坐标: <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.23.1</version> </dependency> 在 "src/main/java/resources" 下新建一个 Log4j 的配置文件 Log4j2.xml: <?xml version="1.0" encoding="UTF-8"?> <!-- Configuration 具有 Appenders 和 Loggers 这两种子节点,每个子节点可以定义多个 --> <configuration> <!-- Appender节点,具有 Console(控制台)、File(文件)、RoolingFile(滚动文件)这三种类型的子节点 --> <Appenders> <!-- 输出日志信息到控制台 --> <Console name="console" target="SYSTEM_OUT"> <!--指定控制日志输出的格式--> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> </Console> <!-- File 节点用来定义输出到指定位置的文件的 Appender,会将所有内容写入到同一个文件中 --> <!-- append属性设置写入新的日志时是追加在原内容后面,还是清除所有内容之后再写入 --> <!-- <File name="allLog" fileName="logs/AlliInOne.log" append="true">--> <!-- <ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>--> <!-- <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{9.9.9.1}(%L) %m%n"/>--> <!-- </File>--> <!-- RollingFile 节点,将日志写入文件,但是允许日志文件根据时间或大小进行滚动,从而避免单个文件过大 --> <!-- fileName 生成的初始日志文件 --> <RollingFile name="rollingFileInfo" fileName="logs/${date:yyyy-MM}/log-info-${date:yyyy-MM-dd}.log" filePattern="logs/${date:yyyy-MM}/log-info-%d{yyyy-MM-dd}-%i.log"> <!-- ThresholdFilter 只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --> <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <!-- PatternLayout 指定控制日志输出的格式,不设置默认为:%m%n --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> <!-- Policies 滚动策略 --> <Policies> <!-- 按时间滚动 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 按大小滚动 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- DefaultRolloverStrategy 设置一个文件下保存的日志文件数量,不设置则默认为同一文件夹下7个文件,超过这个数量后,最老的文件将被删除 --> <DefaultRolloverStrategy max="20"/> </RollingFile> </Appenders> <!-- 在 Loggers 中引入上面定义好的 Appender --> <loggers> <!-- level指定日志级别,从低到高的优先级: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <!-- 设置org.mybatis包下的日志只打印WARN及以上级别 --> <Logger name="org.mybatis" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <!-- 设置org.springframework包下的日志只打印WARN及以上级别 --> <Logger name="org.springframework" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <root level="DEBUG"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </root> </loggers> </configuration> Log4j 配置文件详解:彻底掌握Log4j2 - 蚂蚁小哥 - 博客园 修改 Spring 配置中的 SqlSessionFactoryBean,修改 MyBatis 使用的日志框架为 Log4j2: <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入数据源,dataSource 是在前面配置的数据库连接池--> <property name="dataSource" ref="dataSource"/> <!--从类路径下加载在 mybatis/mappers 包和它的子包中所有的 MyBatis 映射器 XML 文件--> <property name="mapperLocations" value="classpath*:com/wlplove/dao/*.xml"/> <!-- 给包下的所有对象起一个别名,用这个别名直接引用,不需要再加包名 --> <property name="typeAliasesPackage" value="com.wlplove.entity"/> <!-- MyBbatis 配置 --> <property name="configuration"> <bean class="org.apache.ibatis.session.Configuration"> <!-- 指定 MyBatis 所用日志的具体实现 --> <property name="logImpl" value="org.apache.ibatis.logging.log4j2.Log4j2Impl"/> </bean> </property> </bean>
2021年11月07日
1,313 阅读
0 评论
1 点赞
2021-11-05
Spring学习笔记(一) - Bean与依赖注入
目录: 一、Spring简介 二、Bean配置 2.1、基础配置 2.2、别名配置 2.3、作用域 三、Bean的生命周期 3.1、实例化 3.2、属性赋值 3.3、初始化 3.4、使用 3.5、销毁 3.6、示例:通过XML配置自定义初始化和销毁操作 四、实例化Bean的方式 4.1、无参构造方法 4.2、静态工厂 4.3、实例工厂 4.3.1、方式一 4.3.2、方式二(重要) 五、依赖注入(DI) 5.1、setter 注入 5.1.1、注入简单类型 5.1.2、注入引用类型 5.2、构造器注入 5.2.1、注入简单类型 5.2.2、注入引用类型 5.2.3、构造器注入的其他XML配置写法 5.2.3.1、type方式 4.2.3.2、index索引方式 5.3、基于XML文件的自动装配 5.3.1、byType 5.3.2、byName 5.3.3、constructor 5.4、基于注解的自动装配 六、集合的注入 6.1、注入数组 6.2、注入 Set 对象 6.3、注入 List 对象 6.4、注入 Map 类型数据 6.5、注入 property 类型数据 七、Spring容器的核心操作 7.1、创建容器 7.2、从Srping容器获取Bean 7.2.1、根据Bean名称/ID 7.2.2、根据Bean类型获取 7.2.3、根据Bean名称获取并指定类型 八、一图流总结 8.1、Bean: 8.2、依赖注入: 一、Spring简介 Spring 是一个开源的 Java 平台框架,广泛用于构建企业级应用程序。它由 Rod Johnson 在 2003 年首次发布,旨在简化 Java 开发,提供全面的基础设施支持。Spring 的核心特性包括依赖注入(DI)和面向切面编程(AOP),是开发Java EE应用程序的必备。 在 pom.xml 文件中导入 Spring 的坐标依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> 二、Bean配置 Bean 是 Spring 框架中最核心的概念之一,它是构成应用程序主干并由 Spring IoC 容器管理的对象。 Spring Bean 本质上是由 Spring IoC 容器实例化、组装和管理的对象,可以是任何 Java 类的实例,如一个简单的 POJO(Plain Old Java Object),比如一个表示用户信息的 User 类,在 Spring 容器中可以被定义为一个 Bean,然后 Spring 可以对 User 类的实例进行各种诸如依赖注入等的管理操作。除此之外,Bean 也可以是一个复杂的企业级组件。 在 Java 中,对象通常通过 new 关键字来创建,但在 Spring 中,对象的创建和依赖注入由 Spring IoC 容器负责。这种机制允许开发者将对象的生命周期管理和依赖关系交给 Spring 容器,从而简化了开发过程并提高了代码的可维护性和灵活性。 2.1、基础配置 <!-- bean标签用来配置bean id属性是bean的名字,是唯一的,不能重复 class属性是bean的类型,值是全路径类名 --> <bean id="userDao" class="com.wlplove.dao.impl.UserDaoImpl"/> <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl"> <!-- property标签用来配置当前bean中的的属性,需要其有set方法 name属性指定配置的哪一个属性,是属性的名称 ref属性表示参照哪一个bean,是当前容器中存在的bean --> <property name="userDao" ref="userDao"/> </bean> 在 XML 文件中经过上面的配置之后,就将这个类交给了 Spring IoC 容器进行管理,之后需要使用该类时就可以从容器中获取到实例对象了。 2.2、别名配置 name 属性表示 Bean 的别名,可以设置多个,使用逗号、分号、空格分开。 别名配置完成后,就可以通过别名获取 Bean 或者在其他 Bean 的配置中通过别名引用这个 Bean。 <bean id="bookService" name="service service2 bookEbi" class="com.wlplove.service.impl.BookServiceImpl"/> 2.3、作用域 Spring Bean 的 Scope 指的是 Bean 的作用域,它定义了 Bean 实例在 Spring 容器中的生命周期和可见性。一般常用的是 singleton(单例)、prototype(原型/非单例): singleton:默认作用域,Spring 容器只会创建一个 Bean 实例,并在整个应用程序中共享。这个实例从容器启动时被初始化,直到容器销毁才会被释放。这种模式适用于无状态的服务对象,如 DAO 组件、控制器等。 prototype:每次请求 Bean 时都会创建一个新的实例。这些实例由 Spring 容器创建,但容器不会跟踪它们的管理和销毁,这些任务交由 Java 的垃圾回收机制来处理。适用于需要频繁创建且生命周期较短的 Bean,如用户会话数据对象。 作用域可以通过 XML 配置: <bean id="bookDao" class="com.wlplove.dao.impl.BookDaoImpl" scope="singleton"/> 也可以使用注解 @Scope 定义作用域: public class AppConfig { // @Scope("prototype") @Scope("singleton") public MyBean myBean() { return new MyBean(); } } 除此之外,还有 request、session、application 等作用域。 三、Bean的生命周期 Spring Bean 的生命周期包括实例化、属性赋值、初始化、使用和销毁五个阶段。 3.1、实例化 实例化指的是由 Spring 容器创建 Bean 实例的过程。 在这个阶段,Spring 容器通过反射机制来创建 Bean 的实例。 3.2、属性赋值 Spring 容器根据 Bean 信息,为 Bean 的属性进行赋值操作。 这一阶段通常涉及到依赖注入(DI),Spring 容器会自动填充 Bean 的属性并将其他 Bean 的引用注入到当前 Bean 的属性中。 3.3、初始化 初始化阶段是 Spring Bean 生命周期中的一个重要环节,它标志着 Bean 已经准备好被使用。 在这个阶段,Spring 容器会执行一系列初始化操作,其中包括开发者自定义的初始化方法,开发者可以通过以下几种方式自定义初始化操作: XML 配置时在 <bean> 标签中定义属性 init-method 使用 @PostConstruct 注解定义初始化方法 实现接口 InitializingBean 的 afterPropertiesSet() 方法 3.4、使用 这一阶段,Bean 已经被完全初始化,并且可以被 Spring 容器提供给其他组件或服务进行调用。Bean 的使用通常是通过依赖注入(DI)的方式完成的,即在需要使用 Bean 的地方直接注入即可。 3.5、销毁 销毁阶段是 Spring Bean 生命周期的最后一个阶段,它发生在 Bean 不再被需要时。 在这个阶段,Spring 容器会执行一系列的清理操作,包括开发者自定义的 Bean 的销毁方法,开发者可以通过以下几种方式: XML 配置时在 <bean> 标签中定义 destroy-method 属性 使用 @PreDestroy 注解定义销毁方法 实现接口 DisposableBean 的 destroy() 方法 这些操作旨在释放 Bean 所占用的资源,确保系统的稳定性和性能。 3.6、示例:通过XML配置自定义初始化和销毁操作 Java 代码: public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("save ..."); } publid void init() { System.out.println("init ...."); } public void destory() { System.out.println("destory ..."); } } XML 配置: <!-- “init-method”方法指定Bean的初始化方法,“destory-method”方法指定Bean的销毁方法 --> <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl" init-method="init" destroy-method="destory" /> 四、实例化Bean的方式 4.1、无参构造方法 Java 类: public class UserServiceImpl implements UserService { private UserServiceImpl() { System.out.println("constructor is running ...."); } public void save() { System.out.println("save ..."); } } Spring 配置: <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl"/> 在接口继承类中必须要提供无参构造方法,如果不存在,将抛出 BeanCreationException 异常 4.2、静态工厂 Java 类: public class UserServiceImpl implements UserService { // ... } // 工厂类 public class UserServiceFactory { // 静态工厂方法 public static UserService getUserService() { return new UserServiceImpl(); } } Spring 配置: <!-- class属性指定工厂类,factory-method属性指定使用工厂类中的哪个静态方法实例化Bean --> <bean id="userService" class="com.wlplove.factory.UserServiceFactory" factory-method="getUserService"/> 4.3、实例工厂 4.3.1、方式一 Java 类: // 工厂类 public class UserServiceFactory { // 工厂方法(非静态) public UserService getUserService() { return new UserServiceImpl(); } } Spring 配置: <!-- 工厂Bean --> <bean id="userServiceFactory" class="com.wlplove.factory.UserServiceFactory" /> <!-- 用前面定义好的工厂类userServiceFactory中的方法getUserService来实例化userService --> <!-- factory-bean 指定工厂类,factory-method 方法指定用工厂类的哪个方法实例化 Bean --> <bean id="userService" factory-bean="userServiceFactory" factory-method="getUserService" /> 4.3.2、方式二(重要) 工厂对象继承 FactoryBean<T> 这个对象,并重写其中的 getObject() 和 getObjectType() 方法 FactoryBean 是 Spring 框架中用于创建复杂对象的一个特殊接口,它允许开发者创建一个工厂类,用于生成其他对象。这个接口定义了三个主要方法: getObject() 作用:返回由该 FactoryBean 创建的对象实例。这是 FactoryBean 最核心的方法,用于实际创建对象实例。 注意:这个方法可能会抛出异常,因为对象的创建过程可能涉及复杂的逻辑和资源管理。 getObjectType() 作用:返回由该 FactoryBean 创建的对象的类型。这有助于 Spring 容器在运行时了解 Bean 的类型信息,从而进行类型匹配和依赖注入。 默认实现:如果未重写此方法,则默认返回 Object.class。 isSingleton() 作用:指定返回的实例是否为单例。如果返回 true,则表示这个 FactoryBean 返回的对象在整个 Spring 容器中是唯一的;如果返回 false,则每次请求都会创建一个新的实例。 默认实现:如果没有明确指定,默认返回 true,即单例模式。 Java 类: // 省略 UserService 接口与 UserServiceImpl 继承类的定义... public class UserServiceFactoryBean implements FactoryBean<UserService> { @Override public UserServce getObject() throws Exception { return new UserServiceImpl(); } @Override public Class<?> getObjectType() { return UserService.class; } @Override public boolean isSingleton() { // true 返回单例对象,false 返回非单例对象 return ture; } } Spring 配置: <bean id="userService" class="com.wlplove.factory.UserServiceFactoryBean" /> 五、依赖注入(DI) 依赖注入(Dependency Injection,简称 DI)是 Spring 框架的核心概念之一,这种设计模式用于实现控制反转(Inversion of Control,即 IoC)。它的核心思想是:对象的依赖关系由外部容器(如 Spring 容器)在运行时注入,而不是由对象自己创建或查找依赖。 举个例子,假设有一个 UserService 类,它依赖于 UserRepository 类。在没有依赖注入的情况下,UserService 需要自己创建 UserRepository 的实例。这种方式的问题在于,UserService 和 UserRepository 紧密耦合在一起,难以测试和维护。 使用依赖注入后,UserService 不再自己创建 UserRepository,而是通过构造函数、Setter 方法或自动装配的方式,由 Spring 容器提供 UserRepository 的实例。 Spring 提供了三种主要的依赖注入方式:setter 注入、构造器注入、自动装配。 5.1、setter 注入 5.1.1、注入简单类型 Java 类中提供成员的 set 方法: public class User { // 姓名 private String name; // 年龄 private int age; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } Spring 配置中用 <property> 标签来定义具体成员: <!-- 简单类型 (通过 value 属性注入普通类型值) --> <bean id="user" class="com.wlplove.dto.User"> <property name="name" value="test" /> <property name="age" value="20" /> </bean> 5.1.2、注入引用类型 同样的,在 Java 类中提供对象的 set 方法: // 省略接口UserDao接口的定义 ... // 接口继承类 public class UserServiceImpl implements userService { private UserDao userDao; private setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.insert(); } } Spring 配置: <bean id="userDao" class="com.wlplove.dao.UserDao" /> <!-- 引用类型 (通过 ref 属性注入引用类型值) --> <bean id="userServiceImpl" class="com.wlplove.service.UserServiceImpl"> <property name="userDao" ref="userDao" /> </bean> 5.2、构造器注入 在对象创建时,所有的依赖都通过构造器参数传入,类似于 setter 注入需要提供成员 set 方法,构造方法注入需要在类中提供构造方法,并且 XML 配置里使用构造器注入的参数顺序必须要与 Java 类构造方法的形参顺序相同。 5.2.1、注入简单类型 构造方法: public class User { // 姓名 private String name; // 年龄 private int age; public void User(String name, int age) { this.name = name; this.age = age; } } Spring 配置: <!-- 普通类型 (通过 value 属性注入引用类型值,name属性值是构造方法中的形参)--> <bean id="user" class="com.wlplove.dto.User"> <!-- 这里的参数顺序要与构造函数中的形参顺序相同 --> <construct-arg name="name" value="test" /> <construct-arg name="age" value="20" /> </bean> 5.2.2、注入引用类型 // 接口继承类 public class UserServiceImpl implements userService { private UserDao userDao; private UserServiceImpl(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.insert(); } } Spring 配置: <bean id="userDao" class="com.wlplove.dao.UserDao" /> <!-- 引用类型 (通过 ref 属性注入引用类型值,name 属性的值是构造方法形参的值)--> <bean id="userServiceImpl" class="com.wlplove.service.UserServiceImpl"> <constructor-arg name="userDao" ref="userDao" /> </bean> 5.2.3、构造器注入的其他XML配置写法 5.2.3.1、type方式 在 constructor-arg 标签中使用 type 属性: <bean id="userDao" class="com.wlplove.dao.UserDao" /> <bean id="userServiceImpl" class="com.wlplove.service.UserServiceImpl"> <constructor-arg type="int" value="123" /> <constructor-arg type="java.lang.String" value="test" /> <constructor-arg type="com.wlplove.dao.UserDao" ref="userDao" /> </bean> type 方式解决了构造器注入时 name 属性绑定了形参名称从而造成强耦合的问题,如果一个 Bean 中某种类型(比如 int)的属性只有一个,那么可以用这种方式,反之,当相同类型的属性有很多个时,用这种方式就会给所有这种类型的属性都注入相同的值。 4.2.3.2、index索引方式 在 constructor-arg 标签中使用 index 属性: <!-- index索引方式,解决参数类型重复问题,使用索引进行参数匹配对应 --> <bean id="userDao" class="com.wlplove.dao.UserDao" /> <bean id="user" class="com.wlplove.dao.dto.User"> <constructor-arg index="0" value="20" /> <constructor-arg index="1" value="test" /> <constructor-arg index="2" ref="userDao" /> </bean> 5.3、基于XML文件的自动装配 所谓自动装配就是省略手动在 XML 中配置 Bean 依赖的步骤,而使 Spring 容器自动解析 Bean 之间的依赖关系,并将依赖的 Bean 注入到目标 Bean 中。需要注意的是,自动装配只针对于 Bean 中引用类型的依赖,简单类型的依赖无法被自动装配。 5.3.1、byType Spring 容器会根据属性的类型来自动装配。它会在容器中查找与需要注入的属性类型相同的 Bean,并将其注入到该属性中。 要使 Spring 容器按 Bean 类型自动装配,加入 autowire="byType": <bean id="bookService" class="com.wlplove.service.UserServiceImpl" autowire="byType" /> 使用 byType 这种方式,必须保证配置文件中所有 Bean 的 class 属性值是唯一的,否则就会报错 5.3.2、byName Spring 容器会根据属性名称来自动装配,在容器中查找与需要注入的属性名称相同的 Bean,并将其注入到该属性中。严格来说,此处的属性名称并非是指成员变量名称,而是指 set 方法名去掉 set 之后将首字母小写的名称,比如 User 类中 age 属性的 set 方法为 setAge1(),那么将 set 方法处理之后得到的属性名称为 age1,Spring 容器根据属性名称 age1 自动装配,而不是 age。 要使 Spring 容器按 Bean 名称自动装配,加入 autowire="byName": <bean id="bookService" class="com.wlplove.service.UserServiceImpl" autowire="byName" /> 5.3.3、constructor 基于构造函数的自动装配。Spring 容器会查找与构造函数中形参的数量与类型相同的 Bean,并通过构造函数注入。 <bean id="bookService" class="com.wlplove.service.UserServiceImpl" autowire="constructor" /> 5.4、基于注解的自动装配 除了 XML 配置,也可以使用 @Autowired 注解来实现自动装配: 构造器注入:将 @Autowired 注解标注在构造器上,Spring 容器根据构造器参数类型来注入依赖。 Setter方法注入:将 @Autowired 注解标注在 set 方法上,Spring 容器根据 set 方法的名称和参数类型来注入依赖。 字段注入:直接将 @Autowired 注解标注在字段上,Spring 容器根据字段类型来注入依赖。 六、集合的注入 接下来的例子以 setter 注入为例进行说明,构造器注入类似,将 <property></property> 标签修改为 <constructor-arg></constructor-arg> 即可。 6.1、注入数组 <!-- name 属性设置将数据注入哪一个数组 --> <property name="test_array"> <!-- 此处 array 与 list 可以混用 --> <array> <!-- 引用类型 --> <value>123</value> <value>456</value> <value>789</value> <!-- 引用类型 --> <!-- <ref bean="beanId"></ref> --> </array> </property> 6.2、注入 Set 对象 <property name="test_set"> <set> <value>set_qwe1</value> <value>set_asd2</value> <value>set_zxc3</value> <!-- 重复会自动过滤 --> <value>set_zxc3</value> </set> </property> 6.3、注入 List 对象 <property name="test_list"> <!-- 此处 array 与 list 可以混用 --> <list> <value>list_qwe1</value> <value>list_asd2</value> <value>list_zxc3</value> </list> </property> 6.4、注入 Map 类型数据 注入 Map 对象: <property name="test_map"> <map> <entry key="contry" value="China"></entry> <entry key="province" value="Gansu"></entry> <entry key="city" value="Lanzhou"></entry> </map> </property> 6.5、注入 property 类型数据 <property name="test_properties"> <props> <prop key="contry">China</prop> <prop key="province">Gansu</prop> s<prop key="city">Lanzhou</prop> </props> </property> <property> 标签表示 setter 方式注入,构造方式注入 <constructor-arg> 标签内部也可以写 <array>、<list>、<set>、<map>、<props> 标签 List 的底层也是通过数组实现的,所以 <list> 和 <array> 标签可以混用 若要在集合中添加引用类型,只需要把 <value> 标签改成 <ref> 标签,但这种方式用的比较少 七、Spring容器的核心操作 7.1、创建容器 通过类路径来加载配置文件的方式创建容器: ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // 加载多个文件,也就是将多个XML文件的配置都加载到一个Spring容器中: ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext1.xml", "applicationContext2.xml"); 也可以通过文件路径来加载配置文件的方式创建容器: ApplicationContext ctx = new FileSystemXmlApplicationContext("E:\\applicationContext.xml"); // 加载多个文件,也就是将多个XML文件的配置都加载到一个Spring容器中: ApplicationContext ctx = new FileSystemXmlApplicationContext("E:\\applicationContext1.xml", "E:\\applicationContext2.xml"); 7.2、从Srping容器获取Bean 7.2.1、根据Bean名称/ID // 需要类型强制转换 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 7.2.2、根据Bean类型获取 // 参数是 类名.class BookDao bookDao = ctx.getBean(BookDao.class); 当按类型获取 Bean 时,必须保证该类型的 Bean 在 Spring 容器中只有一个,否则会抛出 NoUniqueBeanDefinitionException 异常。 7.2.3、根据Bean名称获取并指定类型 BookDao bookDao = ctx.getBean("bookDao", BookDao.class); 八、一图流总结 8.1、Bean: 8.2、依赖注入:
2021年11月05日
1,294 阅读
0 评论
4 点赞
2021-09-14
目前最流行的版本控制软件:Git的基本使用
前排提示: 本篇博客篇幅较长,建议结合目录查看! 目录: 写在前面 1、关于版本控制系统 定义 版本控制的必要性: 常见的版本控制系统 2、Git与Github 0x01.安装Git 0x02.Github中的一些基本概念 Repository Issue Star Fork Pull Request Watch Wiki Gist 0x03.添加SSH key 0x04.克隆仓库 0x05.初始化仓库 0x06.提交修改 0x07.分支操作 查看分支 建立新分支 切换分支 建立并切换到新分支 推送本地分支到远程仓库 合并分支 删除分支 重命名分支 0x08.标签操作 附注标签 轻量标签 切换标签 推送标签 删除标签 查看所有标签 给提交打标签 写在前面 1、关于版本控制系统 定义 版本控制(Version control)是维护项目的标准作法,能追踪项目从诞生一直到定案的过程。此外,版本控制也是一种软件工程技巧,借此能在软件开发的过程中,确保由不同人所编辑的同一程序文件都得到同步,记录项目内各个模块的改动历程,并为每次改动都编上序号。 一种简单的版本控制形式如下:工程的初代版本为“1.0”,当做了第一次改变后,版本等级改为“1.1”,以此类推。因此,版本控制能提供给开发者将项目恢复到之前任一状态的选择权,这种选择权在设计过程进入死胡同时特别重要。 版本控制的必要性: 常会利用版本控制来追踪维护源代码、文件以及配置文件等的改动,并且提供控制这些改动控制权的程序; 有时候,一个程序同时存有两个以上的版本,例如:在一个稳定版本中程序错误已经被修正、但没有加入新功能;在另一个开发版本则有新的功能正在开发、也有新的错误待解决,这使得同时间需要不同的版本; 此外,为了找出只存在于某一特定版本中(由于修正了某些问题、或新加功能所导致)的程序错误,或找出程序错误出现的版本,开发者也需要比对不同版本的代码以找出问题的位置。 常见的版本控制系统 集中式版本控制系统:由一台或多台主计算机组成中心服务器,所有业务单元和项目版本库都集中存储在这个中心服务器上,开发时,要先从中央服务器取得项目最新的版本,一次开发完毕之后,再将工作量推送给中央服务器。就像是一个图书馆,如果要改一本书的内容,则需要把书先从图书馆借出来,然后修改,改完之后再放回图书馆。 因此,集中式版本控制系统最的大缺点就是中央服务器出了问题,所有人都没法工作了。 常见的集中式版本控制系统有SVN、CVS等。 分布式版本控制系统:分布式版本系统没有绝对的中央服务器,每个人的电脑上都是一个完整的版本库,多个人进行协同工作时,只需将自己的修改与其他人的修改进行交换即可 和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,其中一个人的电脑坏了不要紧,从其他人那里复制一个就可以了。 Git就是常见的分布式版本控制系统之一,也是目前最流行的版本控制系统。 2、Git与Github 准确地说,Git与Github根本不是同一个概念。 Git是指由Linus(就是那位二十多年前徒手撸出Linux内核的大佬)编写的分布式版本控制系统,于2005年以GPL发布。最初目的是为了更好地管理Linux内核开发。 自2002年以来,Linus一直使用BitKeeper作为Linux内核主要的版本控制系统以维护代码。在Linux社区中,主张应该使用开放源代码的软件来作为Linux内核的版本控制系统。Linus曾考虑过采用现成软件作为版本控制系统(例如Monotone),但这些软件都存在一些问题,特别是性能不佳。 2005年,Linux社区中的安德鲁·垂鸠写了一个可以连接BitKeeper的存储库的简单程序,BitKeeper著作权拥有者拉里·麦沃伊便认为安德鲁·垂鸠对BitKeeper内部使用的协议进行了逆向工程,决定收回无偿使用BitKeeper的许可。Linux内核开发团队与BitMover公司进行磋商无果后,Linus决定自行开发版本控制系统以替代BitKeeper,在十天的时间编写出git第一个版本。于是,世界上最流行的版本控制系统就这么戏剧式地诞生了。 而GitHub是通过Git进行版本控制的软件源代码托管服务平台,由GitHub公司(曾称Logical Awesome)的开发者Chris Wanstrath、P. J. Hyett和Thomas Preston-Werner使用Ruby on Rails编写而成,于2007年10月1日开始开发。beta版本开始上线于2008年2月,4月份正式上线。这是他们的logo,名字叫Octocat: 截止到2020年1月,GitHub已经有超过4000万注册用户和1.9亿代码库(包括至少2800万开源代码库),事实上已经成为了世界上最大的代码存放网站和开源社区,国内很多人戏称为“全球最大同性交友网站”。 2018年6月4日晚,微软宣布以75亿美元的股票收购GitHub。 Github服务器在国外,处于半被墙的状态,有时正常访问,有时又打不开。与之类似的代码托管平台Gitee可以看做是国内版的Github,缺点是开源项目不如Github丰富,当然,由于在访问时速度更快,更适合国内用户托管代码。而且,部分开源项目是同时托管在这两个平台上的,所以碰到无法打开的Github项目时,在Gitee上找找也许会有惊喜。 0x01.安装Git Git在全平台均可使用。 Git官网:Git (git-scm.com) 官方中文文档:Git - Book (git-scm.com) Windows系统Git安装包下载链接:Git - Downloads Linux系统安装Git:Git - Download for Linux and Unix Mac系统安装Git:Git - Download for macOS 安装完成之后在控制台中输入git,如果出现如下输出说明安装成功: 前面提到过,Git只是一个分布式版本管理软件,每个人的计算机都是一份完整的版本库,对这份版本库进行修改之后,将每个人的修改进行合并。但是如果不在同一个内网中,合并修改就会变得困难。此时也需要一个中央服务器来辅助进行代码的合并。这也就是Github、Gitee、Gitlab等平台最基本的作用。 因此,我们还需要注册一个Github/Gitee账号,将我们的代码托管到平台上面(从某种角度上将它看成一个专门存放代码的云盘也未尝不可)。Github注册账号及用户界面介绍可以参考这篇文章:从0开始学习 GitHub 系列之「加入 GitHub」 (qq.com),本篇博客不再介绍。 0x02.Github中的一些基本概念 Repository 仓库,即项目,要在GitHub上开源一个项目,那就必须要新建一个Repository。 Issue 问题的意思,举个例子,比如开源的项目,别人发现项目中有bug,或者哪些地方做的不够好,他就可以提个Issue,即问题,提的问题多了,也就是 Issues ,然后开发者看到了这些问题就可以去逐个修复,修复ok了就可以一个个的Close掉。 Star 就是给项目点赞,这个star的含金量还是挺高的。 Fork 这个可以翻译成分叉,你想在某个开源项目的基础上做些改进,然后应用到自己的项目中,这个时候就可以Fork这个项目,与此同时你的GitHub主页上就多了一个项目,只不过这个项目是基于这个开源项目(本质上是在原有项目的基础上新建了一个分支)。而你就可以随心所欲的去改进这个项目了,丝毫不会影响原有项目的代码与结构。 Pull Request 发起请求,这个其实是基于Fork的,还是上面那个例子,如果你在项目基础上做了改进,就可以把自己的改进合并到原有项目里,这个时候你就可以发起一个Pull Request(简称PR),原有项目开发者会收到这个请求,这个时候他会review代码,并且测试觉得OK了,就会接受PR,这个时候新的改进会被合并进原有项目。 Watch 可以理解为观察,如果Watch了某个项目,以后如果这个项目有更新,都会收到关于这个项目的通知提醒。 Wiki 一般来说,项目的主页有README文件基本就够了,但是有些时候项目的一些用法很复杂,就需要有详细的说明文档给使用者。这个时候就可以用Wiki,使用markdown语法即可进行编写。 Gist 如果没有项目可以开源,只是单纯的想分享一些代码片段,那这个时候Gist就派上用场了。 0x03.添加SSH key 当我们对代码进行提交时,Github/Gitee要怎么知道是我们提交的代码,而不是别人提交的呢,所以就需要进行授权来确认我们的身份。 Github和Gitee服务器可以选择使用SSH公钥或GPG公钥来进行授权,这里采用SSH授权方式,提交代码之前需要先添加SSH key配置。大概步骤就是先在本地生成SSH key,然后将本地生成的SSH key添加到Github或者Gitee上。 SSH(Secure Shell)是一种建立在应用层基础上的安全协议,一般用于远程登录会话和其他网络服务。由于在传输过程中对数据进行了加密和压缩,因此可以有效防止远程管理过程中的“中间人攻击”,传输速度也会更快,还能够防止”DNS欺骗“和”IP欺骗“等。 生成SSH密钥: ssh-keygen -t rsa 这句命令的意思是用RSA算法生成密钥(windows系统最好在Git Bash下执行,cmd终端可能并没有安装ssh),执行后出来三次提示均按回车,命令执行完会生成id_rsa(密钥)和id_rsa.pub(公钥)这两个文件。Linux/Mac系统在~/.ssh下,windows系统在C:\Users\用户名\.ssh(用户名是自己电脑的用户名)下,需要设置显示隐藏文件选项才能看到。 将id_rsa.pub用文本编辑器打开,复制里面的内容。 添加公钥到Github/Gitee: 进入Github/Gitee的设置界面,在左侧选项列表找到SSH keys选项 将刚才复制的公钥粘贴上去,公钥标题可写可不写,然后保存,这样就完成了公钥的添加。 0x04.克隆仓库 说来惭愧,这是我接触到Github之后很长时间内最常用的操作(因为就只会这一个操作)。命令很简单: git clone [仓库链接] 这个命令的作用就是从Github上下载别人仓库的项目文件,可能是从clone直接音译过来的原因,这个操作一般都称克隆,而不叫下载。 克隆操作只需要有远程仓库链接即可,不需要Github账户也可以进行。克隆完之后项目文件的位置就是执行命令时所处的文件夹。 远程仓库链接在项目主页就可以找到: 0x05.初始化仓库 所谓初始化本地仓库,个人理解就是向本地的项目根目录文件夹中加入一些Git配置文件,使其可以被Git识别以进行版本控制,因为项目文件夹是不能直接进行版本控制的。 初始化本地仓库命令很简单,进入本地项目文件夹(或者用空文件夹),在该目录下执行: git init 也可以在命令后面加入文件夹路径,将指定文件夹初始化成本地仓库: git init [项目文件夹名路径] 项目初始化成功会有Initialized empty Git repository in xxxxxxx的提示,原项目文件夹中多出一个.git隐藏文件夹。此时初始化的本地项目还没有关联到远程仓库。 当然,有本地仓库还不行,我们本意是要把本地仓库推送到远程仓库,因此,还需要在Github/Gitee上建一个远程仓库。点击网站右上角加号,找到“New Repository(新建仓库)” 上图最后三项是用来初始化远程仓库的,如果这三项都不选就创建了仓库,就会提示用命令行来手动初始化远程仓库(所以建议对命令行不感冒的同学直接使用自带的初始化操作)。 来记录一下用命令行手动初始化远程仓库的步骤: 先在本地初始化好的Git项目中新建一个README.md项目说明文件(也可以是别的文件名) 在项目目录下执行命令与远程仓库进行关联: git remote add origin [远程仓库链接] 依次执行以下命令向暂存区加入修改文件,并编辑提交信息 git add README.md # 引号中就是本次提交信息,可修改 git commit -m "first commit" 向远程仓库推送本地仓库文件: Gitee只执行这条命令即可推送: git push -u origin master 从2020年10月开始,Github的默认分支从master变成了main,因此还需要将本地默认主分支重命名为main才能推送成功: git branch -M main git push -u origin main 如果不重命名主分支,就会出现“error: src refspec main does not match any,error: failed to push some refs to ..”的错误。 上述命令执行完之后,再刷新远程仓库界面,就进入了初始化好的远程仓库: 对于都已经初始化过的本地空仓库与远程仓库,使其建立关联可以这样做: # 先关联远程仓库 git remote add origin [仓库远程链接] # 再将远程仓库内容拉取到本地 git pull origin master 0x06.提交修改 所谓修改,就是相对于上次提交之后项目发生的改变(项目文件的增、删、改)。 其中要涉及到push和pull这两个互为相反的概念: Push:直译就是“推”的意思,这个操作可以把本地代码推到远程仓库,这样本地仓库跟远程仓库就可以保持同步了。 Pull:直译为“拉”的意思,如果别人提交代码到远程仓库,这个时候本地仓库代码与远程仓库代码并不一致,所以需要把远程仓库的最新代码拉下来,以保证两端代码的同步。 同时,提交代码前最好设置一下提交者的名字与邮箱,方便在commit记录里显示: git config —global user.name "名字" git config —global user.email "邮箱" 通常一次完整的提交过程如下: 将修改过的文件加入暂存区: git add [修改的文件或者目录] # .表示此目录下所有文件,一次提交的文件较多时,可以使用此命令 git add . 确认提交暂存区中的文件: # -m表示附加提交信息,后面的内容是关于提交的信息说明 git commit -m "提交信息" git add是先把改动添加到一个“暂存区”,可以理解成是一个缓存区域,临时保存改动,而git commit才是最后真正的提交。这样做的好处是防止误提交。 最后将代码推送到远程仓库指定分支,即可完成一次代码提(其中注意,最后提交时Gitee与Github的分支名有所不同): # 推送代码到指定分支 git push origin [分支名] # Github默认分支是main,用以下命令: git push origin main # Gitee默认分支是master,用以下命令: git push origin master 这里的origin是给远程仓库起的名字,当然名字并不唯一,可以是其他名字,只是因为习惯,一般都起名为origin。 一般在多人协作时,为了不产生代码冲突,提交代码前最好进行一次Pull操作: git pull origin [分支名] 查看git仓库当前状态,比如当前所在分支、被修改过的文件、未提交的文件等等: git status 查看提交时产生的所有commit记录: git log 0x07.分支操作 branch即分支的意思,分支的概念在团队协作的时候很重要,假设两个人都在做同一 个项目,这个时候分支就是保证两人能协同合作的最大利器了。举个例子,A, B两人在做同一个项目不同的模块,这个时候A新建了一个分支叫a,B新建了一个分支叫b,这样 A、B做的所有代码改动都在各自的分支上,互不影响,等到都把各自的模块做完 了,最后再统一把分支合并到master主分支。 在本地执行git init命令初始化仓库时默认生成一个主分支master。 而远程仓库的情况就有所不同了,曾经Github远程仓库的默认主分支也是master,但是去年(2020)10月份之后Github将默认主分支名称从master改成了main(据说是因为master这个词意为奴隶的主人,含有种族歧视意味),这也是在前面手动初始化Github仓库时要将主分支名重命名为main的原因。 而Gitee的主分支名称依然是master。 查看分支 查看本地分支列表: git branch 查看远程分支列表: git branch -r 建立新分支 git branch [分支名] 需要注意的是,新创建的分支的内容与当前所在的分支的内容相同,即新分支是基于当前所在的分支而创建的。 当我们建立了新分支以后,默认不会切换到新分支上,当前做出的任何更改还是基于当前所在的分支,所以需要切换分支。 切换分支 git checkout [分支名] # 切换到新分支之后手动拉取最新内容 git pull origin [分支名] 此时进行的改动就是在新分支下面了。当然,也有办法一步到位,加入-b参数即可。 建立并切换到新分支 git checkout -b [分支名] 推送本地分支到远程仓库 在本地建完新分支之后,就可以将本地新分支推送到远程仓库了,以保证两端同步 git push origin [新分支名] 如果本地推送到远程的分支想取另一个名字,那么可以用这条命令: git push origin [本地分支名]:[远程新分支名] 但是强烈不建议这样,这会导致管理混乱,建议本地分支跟远程分支名要保持 一致。 合并分支 当团队中不同成员都完成了开发之后,就可以将改动都合并到一块了。 # 首先切换到要合并到的分支上来,比如master(main)分支或是指定分支 git checkout [分支名]/main/master # 进行合并,将指定分支合并到当前所在的分支(即上一步切换到的分支)上来 git merge [指定分支] 在没有冲突的情况下,代码就可以合并完成了。合并完记得把新代码push到远程仓库。 删除分支 分支建错或者该分支的代码已经顺利合并到其他分支的时候,就可以删除分支了: git branch -d [分支名] 有些时候可能会删除失败,比如该分支的代码还没有合并到master或者其他分支,执行删除分支操作就会失败,Git会提示这个分支上还有未合并的代码,但是也可以强制删除分支: git branch -D [分支名] 以上仅仅为删除本地分支,若要删除远程分支可以可以运行带有 --delete 选项的 git push 命令: git push origin --delete [远程分支名] 重命名分支 将A分支重命名为B分支: git branch -m A B 类似于删除分支,无法重命名时,也可以强制重命名: git branch -M A B 如果是重命名远程分支,推荐的做法是: 删除远程待修改分支 push本地新分支名到远程 0x08.标签操作 开发的时候经常有版本的概念,比如v1.0、v1.1之类的,不同的版本肯定对应不同的代码,所以给代码打上标签,标签名可以是版本号或者其它标记。 Git 支持两种标签:附注标签(annotated)与轻量标签(lightweight)。 附注标签 附注标签是存储在Git数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、邮件地址、日期时间, 此外还有一个标签信息,并且可以使用GNU Privacy Guard(GPG)签名并验证。 通常建议创建附注标签,这样就可以拥有以上所有信息 添加附注标签信息用这条命令: git tag -a [标签名] -m "标签信息" -m参数为可选的,表示指定一条存储在标签中的信息。如果省略-m参数,那么Git会自动打开编辑器,让我们写一句标签信息,就像给提交写注解一样。 利用git show命令可以查看标签信息与对应的提交信息: git show [标签名] 输出会显示打标签者的信息、打标签的日期时间、附注信息与具体的提交信息。 轻量标签 如果只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么就可以用轻量标签。 轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。本质上是将提交校验和存储到一个文件中——没有保存任何其他信息。 创建轻量标签,不需要使用 -a、-s 或 -m 选项,只需要提供标签名: git tag [标签名] 同样的,利用git show命令查看标签信息与对应的提交信息,输出只会显示出提交信息,不会看到额外的标签信息。 切换标签 当要切换到某个tag时,命令与切换分支类似: git checkout [标签名]; 推送标签 同样的,向远程仓库推送单个标签的命令与推送分支也是类似的: git push origin [标签名] 如果一次推送多个标签,可以使用带有--tags的git push命令: git push origin --tags 这条命令会将所有不在远程仓库服务器上的标签全部推送到远程仓库。 删除标签 删除本地标签: git tag -d [标签名] 上述命令并不会从远程仓库中移除这个标签,从远程仓库移除标签有两种办法: git push <remote> :[标签名称] 这种操作的含义是,将冒号前面的空值推送到远程标签名,从而实现删除的效果。 第二种方式相对来说更直观: git push origin --delete [标签名] 查看所有标签 执行git tag命令,就可以列出所有标签: git tag 默认是以字母顺序排列标签。 当然,可带上可选的 -l 选项或者 --list选项,以匹配特定标签名: git tag -l "通配符" # 或者 git tag --list "通配符" 例如,只查阅v2.*版本的标签名: git tag -l "v2.*" 给提交打标签 假设在过去某一个时刻提交了项目更改,后期才想起来忘记给项目打标签了,那么也可以在之后补上标签: git tag -a [标签名] [校验和] 与创建标签命令不同,需要在标签名之后添加一个校验和选项(也可以是部分校验和)。 通过以下命令可以查看每一次提交的校验和与对应的提交信息: git log --pretty=oneline 参考资料: 微信公众号 - stormzhang:从0开始学习Github系列文章 Git 教程 | 菜鸟教程 (runoob.com) Git - Book (git-scm.com) 版本控制 - 维基百科,自由的百科全书 (wikipedia.org) git - 维基百科,自由的百科全书 (wikipedia.org) GitHub - 维基百科,自由的百科全书 (wikipedia.org)
2021年09月14日
1,491 阅读
0 评论
0 点赞
2021-06-18
在IDEA中配置Maven开发环境
目录: 前言 1. 下载Maven安装文件 2.解压并配置环境变量 2.1、windows端 2.2、Linux端 3.设置IDEA 3.1 修改Maven全局配置文件 3.2 修改路径 3.3 导入Maven依赖 环境说明: 系统:win10专业版 deepin V20 IDE:IDEA 2020.3 java:jdk1.8 Maven:3.8.1 前言 Maven是一个构建自动化工具,主要用于Java项目,由Apache软件基金会托管,它以前是Jakarta项目的一部分。Maven还可用于构建和管理用 C#、Ruby、Scala 和其他语言编写的项目。 Maven解决了构建软件的两个方面:软件是如何构建的,以及它的依赖关系。与早期的工具(如Apache Ant)不同,它对构建过程使用约定,并且只需要写下异常。 XML 文件描述了正在构建的软件项目、它对其他外部模块和组件的依赖、构建顺序、目录和所需的插件。它带有预定义的目标,用于执行某些明确定义的任务,例如代码编译及其打包。 Maven从一个或多个存储库(例如Maven 2 Central Repository)动态下载Java库和Maven插件,并将它们存储在本地缓存中。下载工件的本地缓存也可以使用本地项目创建的工件进行更新。公共存储库也可以更新。 Maven官网:http://maven.apache.org/ 1. 下载Maven安装文件 Maven下载页面:http://maven.apache.org/download.cgi 进入下载页面,根据不同的系统选择前两个二进制文件之一下载就可以了。如果打算自行构建Maven,那就下载后面的源码文件。 2.解压并配置环境变量 部分参考资料:Maven – Installing Apache Maven 2.1、windows端 将下载下来的“.zip”压缩文件解压,这里以解压到“D:\Software”为例进行说明。 “计算机”图标上点击右键->属性->高级系统设置(win10 20H2需要在属性窗口的“相关设置”标签中才能找到高级系统设置),在高级系统设置窗口的右下角点击“环境变量”。 “环境变量”分为两种,一种是“用户变量”,这里面配置的环境变量只适用于当前计算机用户,另一种是“系统变量”,适用于这台计算机上的所有用户。具体设置成哪种环境变量看个人习惯。 添加如下两条环境变量,其中MAVEN_HOME的值是Maven文件的解压路径: 环境变量名称 环境变量值 MAVEN_HOME D:\Software\apache-maven-3.8.1 Path %MAVEN_HOME%\bin 其实第一个环境变量的名称并不是固定的,在其他的配置环境变量的教程中名称也可能不同。这个只是习惯而已,只要保证环境变量值没什么问题即可。 第二条Path也可以写成“D:\Software\apache-maven-3.8.1\bin”,这里引用了上条设置的MAVEN_HOME,表示的是Maven安装路径下的bin文件夹 全都添加完之后,两连“确定”完成环境变量的配置。 2.2、Linux端 Linux下也可以用以下命令下载安装包: wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz 下载下来的是一个后缀名为“.tar.gz”的压缩包。解压压缩包到/usr/下: sudo tar -xvf apache-maven-3.8.1-bin.tar.gz -C /usr/ # 当然解压目录不一定非得是/usr/,换成其他目录也可以,后面配置环境变量时目录就要修改 修改环境变量,编辑/etc/profile文件: sudo nano /etc/profile 在末尾加入以下环境变量,“/usr/apache-maven-3.8.1”是Maven安装文件所在的目录: export PATH=/usr/apache-maven-3.8.1/bin:$PATH 然后ctrl + o保存,ctrl + x退出,再输入以下命令使环境变量生效: source /etc/profile 至此就算配置好了环境变量。使用“mvn -v”命令检验是否配置成功,若无法识别命令,部分Linux环境下可能还需要重启一遍电脑才能生效。 3.设置IDEA 此处以Win10下的IDEA开发环境为例,Linux下相关操作都是一样的。 在cmd控制台窗口中输入以下命令查看Maven版本,检验是否配置成功: mvn -v 没有错误的话,输出结果是这样: 3.1 修改Maven全局配置文件 Maven有一个全局配置文件,里面是Maven的一些设置,该文件存放在Maven安装路径的conf文件夹中,修改的就是这个配置文件。关于这个文件的详解可以看这篇:Maven全局配置文件settings.xml详解 - 洪墨水 - 博客园 (cnblogs.com) Maven需要一个文件夹来存放从Maven仓库下载到本地的依赖包,为了减少对系统盘的空间占用,建议将这个文件夹设置到其他分区。找到配置文件里的settings标签,在标签里面加上: <!-- 中间的路径是本地Maven依赖包的存放路径 --> <localRepository>D:\programmeSoftware\MavenRepository</localRepository> Maven仓库在国外,在国内下载速度比较慢,所以还需要将镜像源更改为国内的镜像源。找到<mirrors>标签,往标签内加入阿里云的镜像源配置: <mirror> <id>nexus-aliyun</id> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> 3.2 修改路径 首先在IDEA中新建一个Maven项目,步骤与新建普通Java项目类似,项目类型选择成Maven。 依次点击“File”->“settings”(或者快捷键Ctrl+Alt+s)打开设置界面,然后选择“Build,Execution,Deployment”->“Maven”,设置如下: “User settings file”是Maven全局配置文件的存放路径,“Local repository”是从Maven仓库下载到本地的依赖包的存放路径。设置完了之后点击右下角“Apply”。 需要注意的是,这个设置仅适用于现在打开的Maven项目,为了将这个更改应用到新建的Maven项目上,还需要再进行设置。依次点击“File”->“New Projects Settings”->“Settings for New Projects...”,同样选择“Build,Execution,Deployment”->“Maven”,进行与上面同样的设置即可。 3.3 导入Maven依赖 Maven仓库地址:Maven Repository: Search/Browse/Explore (mvnrepository.com) 项目里用到的依赖包都是从这个网站上找的,以Mybatis为例,说一下依赖包的导入方式。 在网站顶部的搜索栏中搜索“Mabatis” 选择第一项,然后会看到该软件有很多个不同的版本,版本可以随便选择,但是一般为了防止项目中出现与软件版本相关的这类“玄学问题”,还是选择后面使用人数多的一项吧 点击版本号即可进入该版本界面,复制下方“Maven”标签下的那一串<dependency>标签 然后打开项目根目录下的pom.xml文件,将内容粘贴至<dependencies>(这个是复数的dependency)标签内部,注意缩进。导入依赖的第一步,完成。 当然由于只是导入了配置,本地并没有相应的依赖包,所以会看到粘贴的配置中会有红线报错,碰到报错先别慌,看第二步。此时需要在IDEA中要重载一遍项目的Maven依赖配置。有这么几种方法: 在左侧文件目录中的项目名称上单击右键,依次选择“Maven”->“Reload project” 在IDEA窗口右侧列表找到“Maven”,并单击展开菜单,点击菜单左上角刷新重载按钮 在打开的pom.xml文件界面上单击右键(只有在pom.xml文件上单击右键才可以,其他文件单击右键选项中没有Maven),依次选择“Maven”->“Reload project” 不管使用哪一种方式,最后结果都是窗口右下角会出现一个进度条,开始往本地下载pom.xml文件中导入的依赖项。等待这个进度条走完,原来的报错也就消失了。 在以后修改或添加了Maven依赖以后,都可以用这几种方法重新载入项目的Maven依赖配置。
2021年06月18日
1,474 阅读
0 评论
0 点赞
2021-05-31
Maven项目中的MyBatis配置
目录: 一、简介 二、创建项目 2.1、导入 Maven 依赖 2.2、创建 mybatis 核心配置文件 3.3、编写工具类 3.4、编写代码 实体类 Dao 接口 UserMapper 接口实现 UserMapper.xml 3.5、测试 三、问题 1、找不到 mapper.xml 文件 2、SSL 连接问题 环境说明: IDE:IDEA 2020.03 Java:jdk 1.8 MyBatis版本:3.5.3 mysql:5.5 mysql-connector-java:5.1.47 Junit:5.7.0 官方文档: mybatis – MyBatis 3 | 简介 Github 地址: GitHub - mybatis/mybatis-3: MyBatis SQL mapper framework for Java Maven 仓库地址: Maven Repository: org.mybatis » mybatis (mvnrepository.com) 一、简介 MyBatis 是一款优秀的持久层框架 支持自定义 SQL、存储过程以及高级映射。 MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。 MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。 MyBatis 本是 apache 的一个开源项目 iBatis,2010 年这个项目由 apache 迁移到了 google code,并且改名为 MyBatis。 2013 年 11 月迁移到 Github。 二、创建项目 准备数据库,设置字符集与排序规则为 utf-8,否则无法正常插入中文字符。 然后执行以下 SQL 语句: -- 创建表 CREATE TABLE user(id INT NOT NULL AUTO_INCREMENT primary key,name char(20),updateTime datetime); -- 插入两条数据 INSERT INTO user(name,updateTime) value("张三",sysdate()); INSERT INTO user(name,updateTime) value("李四",sysdate()); 并且在 idea 中建好一个 Maven 项目。 2.1、导入 Maven 依赖 项目根目录下的 pom.xml 文件配置 Maven 依赖,在这个配置文件中加入以下依赖的坐标: <dependencies> <!--Mybatis--> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <!--mysql驱动--> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--Junit--> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.0</version> <scope>test</scope> </dependency> </dependencies> 2.2、创建 mybatis 核心配置文件 文件名:mybatis-config / mybatis-cfg,或其他 文件模板及说明:mybatis – MyBatis 3 | 入门 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 打印sql日志 --> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- MySQL8.0以下的驱动名叫com.mysql.jdbc.Driver MySQL8.0以上的驱动名是com.mysql.cj.jdbc.Driver --> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!-- 每一个mapper.xml配置文件都需要在mybaits核心文件中注册 --> <mappers> <!-- 使用文件路径的方式配置 --> <!-- <mapper resource="com/wlplove/dao/AtlasMapper.xml"/> --> <!-- 也可以使用类的方式进行配置 --> <mapper class="com.wlplove.dao.AtlasMapper"/> </mappers> </configuration> 其中,在这个配置文件的 <dataSource> 标签中定义了数据库连接信息,这里将信息写成了固定的死值。还有一种更灵活的方式就是从配置文件中读取信息,在 resources 目录下再新建一个数据库配置文件 jdbc.properties,里面写入数据库信息: # MySQL8.0以下的驱动名叫com.mysql.jdbc.Driver MySQL8.0以上的驱动名是com.mysql.cj.jdbc.Driver driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/pic?useSSL=false&useUnicode=true&characterEncoding=UTF-8 username=root password=root # 或者也可以配置成以下形式: #driver:com.mysql.jdbc.Driver #url:jdbc:mysql://localhost:3306/mybatis?useSSL=false&setUnicode=true&characterEncoding=utf8 #username:root #password:root 修改配置文件中的数据库信息部分为引用外部配置: <!-- 配置文件的路径 --> <properties resource="jdbc-config.properties"/> <dataSource type="POOLED"> <!-- MySQL8.0以下的驱动名叫com.mysql.jdbc.Driver MySQL8.0以上的驱动名是com.mysql.cj.jdbc.Driver --> <property name="driver" value="${driver}"/> <!-- 使用属性占位符 ${} 读取 property 文件中的属性 --> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> 3.3、编写工具类 将加载 SqlSession 的过程写成一个工具类,方便调用: public class MyBatisUtil { /** * 根据 XML 配置文件初始化出 SqlSessionFactory,并获取到 SqlSession 对象 * @return sqlSession */ public static SqlSession getSqlSession() { SqlSession sqlSession = null; try { String xmlFileResource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(xmlFileResource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); sqlSession = sqlSessionFactory.openSession(); } catch (Exception e) { e.printStackTrace(); } return sqlSession; } } 3.4、编写代码 实体类 即业务中涉及到的类,并且包括构造方法、getter 方法、setter 方法以及 toString() 方法 public class User { private int id; private String name; private Date updateTime; // 构造方法、set方法、get方法、toString方法略.... } Dao 接口 UserMapper public interface UserMapper { List<User> getUserList(); } 接口实现 UserMapper.xml 原来的 UserDaoImpl 转换为一个接口的 Mapper 映射文件: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace绑定一个Dao/mapper接口 --> <mapper namespace="com.wlplove.dao.UserMapper"> <!-- 查询语句 --> <!-- 注意其中的id,和resultType返回类型的名称 --> <select id="getUserList" resultType="com.wlplove.pojo.User"> SELECT * FROM mybatis.user; </select> </mapper> 定义好 Mybatis 的这个 Mapper 映射文件之后,需要在 Mybatis 的配置文件中注册一下才能正常调用: <!-- 每一个mapper.xml配置文件都需要在Mybaits核心文件中注册,有这么两种方式注册: --> <mappers> <!-- 使用文件路径的方式 --> <!-- <mapper resource="com/wlplove/dao/AtlasMapper.xml"/> --> <!-- 也可以使用类的方式 --> <mapper class="com.wlplove.dao.AtlasMapper"/> </mappers> 3.5、测试 只要在前面导入了 Junit 的依赖之后,就可以写一个单元测试方法调用写好的接口,单元测试方法没有返回值,没有参数,可以像 main 方法一样直接执行。 class UserMapperTest { // 每一个单元测试方法前面加入 @Test 注解 @Test void getUserList() { // 获取sqlSession对象 SqlSession sqlSession = MybatisUtil.getSqlSession(); // 执行sql UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } // 关闭sqlSession sqlSession.close(); } } 三、问题 1、找不到 mapper.xml 文件 报错信息:Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/wlplove/dao/UserMapper.xml 原因是 Maven 在打包的时候,默认打包 src/main/java 下的 class 文件与 src/main/resources 下的配置文件,没有将该路径下的 mapper 配置文件打包进来,导致运行时候找不到 mapper 文件而报错。 解决方法:手动指定资源文件的位置,参考:mybatis:Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource_在路上s的博客-CSDN博客 修改 pom.xml 文件,在里面加入以下内容,然后更新 Maven 配置即可: <build> <!-- **.xml写在src找不到问题解决方案 --> <resources> <resource> <!-- directory:指定资源文件的位置 --> <directory>src/main/java</directory> <includes> <!-- “**” 表示任意级目录 “*”表示任意任意文件 --> <!-- mvn resources:resources :对资源做出处理,先于compile阶段 --> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <!-- filtering:开启过滤,用指定的参数替换directory下的文件中的参数(eg. ${name}) --> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> </build> 2、SSL 连接问题 报错信息: WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. 翻译过来就是: 警告:不建议在没有服务器身份验证的情况下建立SSL连接。根据MySQL 5.5.45+、5.6.26+和5.7.6+的要求,如果没有设置显式选项,则默认情况下必须建立SSL连接。为了符合不使用SSL的现有应用程序,verifyServerCertificate属性设置为“false”。您需要通过设置useSSL=false来显式禁用SSL,或者设置useSSL=true并为服务器证书验证提供信任存储。 在数据库的连接参数中添加不使用 SSL 连接的参数 useSSL=false 即可解决: <property name="url" value="jdbc:mysql://localhost:3306/practice?setUnicode=true&characterEncoding=utf8&useSSL=false"/> 参考: 史上最详细mybatis与spring整合教程-腾讯云开发者社区-腾讯云 (tencent.com)
2021年05月31日
1,442 阅读
0 评论
0 点赞
2021-05-25
【踩坑实录】mybatis项目报错:“Caused by: .....Exception: 1 字节的 UTF-8 序列的字节 1 无效”
环境说明: 系统:win10 专业版 开发环境:IDEA JDK版本:1.8 mysql:5.5 mybatis:3.5.3 Junit:5.7.0 问题再现: 运行mybatis项目时,控制台出现报错信息: Caused by: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: 1 字节的 UTF-8 序列的字节 1 无效 错误原因: 归根结底是编码的原因,xml文件开头的文档编码设置为了UTF-8: 而由于项目本身的默认编码是GBK,因此xml文件保存时的编码是GBK,声明的xml文档编码与实际编码不一致,就出现了问题 解决方法: 更改项目编码即可。 在IDEA界面打开setting(点击File->setting或者快捷键Ctrl+Alt+S),依次选择Editor->File encodings,将Project Encoding的值从GBK更改为UTF-8。 再次运行,问题消失。
2021年05月25日
1,439 阅读
0 评论
0 点赞
2021-05-25
【踩坑实录】Maven项目报错:java.lang.ExceptionInInitializerError
环境说明: 系统:win10 专业版 开发环境:IDEA JDK版本:1.8 mysql:5.5 mybatis:3.5.3 Junit:5.7.0 问题再现: Maven项目运行时报错,控制台报错信息如下: java.lang.ExceptionInInitializerError at com.langp.dao.UserMapperTest.getUserList(UserMapperTest.java:26) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ······ Caused by: org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in com/langp/dao/UserMapper.xml Process finished with exit code -1 错误原因: 程序在编译过程中找不到对应的配置文件就会报错,但是对应的配置文件却是的的确确存在于项目中的,可是在生成的测试结果target对应目录下找不到对应配置文件,这是因为Maven项目中默认资源配置目录是src/main/resource,而实际有些配置文件会放在src/main/java目录下,就会导致项目编译时导出不了这些配置文件。所以我们需要手动配置资源过滤,使src/main/java的”.properties“文件和”.xml“文件可被导出到测试结果的target文件夹中。 解决方法: 最简单的方式就是将对应的Mapper.xml文件复制到生成测试结果的target文件夹下对应的目录中,但是只要在Maven中执行一次clear操作,target文件夹就被清除了,下次编译时还要重新复制过去。所以还有种更简单的方法: 在Maven项目的配置文件”pom.xml“中添加如下过滤配置信息: <!-- 在build中配置resources,来防止资源导出失败的问题 --> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> 然后,在IDEA中右键依次选择”Maven“->”Reload project“,重新载入依次Maven配置信息即可。
2021年05月25日
2,052 阅读
0 评论
0 点赞
2021-05-25
踩坑实录|mybatis项目报错:...Exception: Type interface UserMapper is not known to the MapperRegistry
环境说明: 系统:win10 专业版 开发环境:IDEA JDK版本:1.8 mysql:5.5 mybatis:3.5.3 Junit:5.7.0 问题再现: mybatis项目运行时报错,报错信息如下: org.apache.ibatis.binding.BindingException: Type interface com.langp.dao.UserMapper is not known to the MapperRegistry. at org.apache.ibatis.binding.MapperRegistry.getMapper(MapperRegistry.java:47) at org.apache.ibatis.session.Configuration.getMapper(Configuration.java:779) at com.langp.dao.UserMapperTest.getUserList(UserMapperTest.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.lang.reflect.Method.invoke(Method.java:498) ····· Process finished with exit code -1 错误原因: 报错信息中出现了Type interface com.langp.dao.UserMapper is not known to the MapperRegistry,简单翻译一下就是:类型接口com.langp.dao.UserMapper不为MapperRegistry所知。 所以这个错误肯定是与mapper有关系的。每一个Mapper.xml都需要在mybatis核心配置文件中进行注册,由于mybatis的核心配置文件mybatis-config.xml中缺少对应接口的Mapper.xml,所以运行时就会报错。 解决方法: 在mybatis的核心配置文件中添加如下内容: <!-- 每一个mapper.xml配置文件都需要在mybaits核心文件中注册 --> <mappers> <mapper resource="com/langp/dao/UserMapper.xml"></mapper> </mappers> 其中,resource属性的值是接口对应Mapper.xml文件。添加之后即可解决。
2021年05月25日
2,648 阅读
0 评论
1 点赞
2021-05-24
Java总结:JDBC连接操作数据库(一)
目录: 前言 一、JDBC结构 1.Java程序 2.JDBC管理器 3.驱动程序 4.数据库 二、JDBC编程的步骤 1、导入包 2、加载驱动程序 3、设置JDBC的连接地址信息 4、创建数据库连接 5、使用SQL语句操作数据库 5.1.Statement接口方法创建表: 5.2.PreparedStatement接口: 6、关闭连接 三、相关的类与方法 1、DriverManager类 ——管理驱动 2、Connection接口 ——建立连接 3、Statement接口 ——执行SQL语句 4、PreparedStatement接口 ——执行SQL语句 5、ResultSet接口 ——存放查询之后返回的结果 前言 Java Database Connectivity简称JDBC,属于Java核心API的一部分,是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口。支持ANSI SQL-92标准,通过调用这些类和接口提供的成员方法,我们可以方便地连接各种不同的数据库,进而使用标准的SQL命令对数据库进行查询、插入、删除、更新等操作。 一、JDBC结构 1.Java程序 主要功能是根据JDBC方法实现对数据库的访问和操作。 主要任务有:请求与数据库建立连接,向数据库发送SQL请求,为结果集定义存储应用和数据类型,查询结果,处理错误,控制传输、提交及关闭连接等。 2.JDBC管理器 即驱动程序管理器,动态地管理和维护数据库查询查询所需要的所有驱动程序对象,实现Java程序与特定驱动程序的连接。 主要任务有:为特定数据库选择驱动程序,处理JDBC初始化调用,为每个驱动程序提供JDBC功能的入口,为JDBC调用执行参数等 3.驱动程序 主要任务:建立与数据库的连接,向数据库发送请求,用户程序请求是执行编译,将错误代码格式化成标准的JDBC错误代码。 编程所使用的数据库系统不同,所需要的驱动程序也有所不同。 4.数据库 按数据结构来存储和管理数据的计算机软件。 常见的数据库比如mysql、Oracle、SqlServer等。 二、JDBC编程的步骤 一次完整的JDBC实现过程分为以下几步: 1、导入包 在程序首部将相关的包导入程序 import java.sql.*; 2、加载驱动程序 使用Class.forName()方法来加载相应的驱动程序。不同数据库所需要加载的驱动程序也不同: // 加载mysql的驱动程序 Class.forName("com.mysql.jdbc.Driver"); //加载oracle的驱动程序 Class.forName("oracle.jdbc.driver.oracleDriver"); 3、设置JDBC的连接地址信息 指定JDBC要连接的地址、端口、数据库、用户名、密码等信息 String username = "root"; String password = "root"; String url = "jdbc:mysql://localhost:3306/test"; // 如果要往表中插入中文,还需要设置编码为utf-8 String url = "jdbc:mysql://localhost:3306/test?seUnicode=true&characterEncoding=utf8"; 其中,"jdbc:mysql"是连接协议,“localhost”是连接地址,“3306”是mysql的连接端口(mysql的默认连接端口是3306),“test”是要连接操作的数据库。 4、创建数据库连接 DriverManager 类中的getConnection() 方法用上一步设置好的url作为参数来创建一个连接对象,并返回这个连接对象给Connection的实例。 //url是上一步创建的连接地址 Connection conn = DriverManager.getConnection(url,username,password); 5、使用SQL语句操作数据库 JDBC中执行SQL语句可以使用Statement接口以及其子接口PreparedStatement接口,下面分别使用不同接口来举例简单说明其用法: 5.1.Statement接口方法创建表: /** * 例子:Statement接口执行创建表,并且插入一组数据 */ // 在当前数据库下创建一个学生表,表中包含主键字段id、姓名name、以及更新时间updatetime String sql1 = "create table student(id int NOT NULL AUTO_INCREMENT primary key,name char(10),updateTime Datetime)"; // 向创建的student表添加一组信息 String sql2 = "insert into student(name,updatetime) values('qwe',sysdate())"; // 创建一个Statement对象 Statement st = conn.createStatement(); // 用executeUpdate()函数执行不返回任何内容的sql语句,如INSERT、UPDATE、DELETE以及其他DDL(数据定义语言)等。其参数为SQL语句 // 执行建表SQL语句 st.executeUpdate(sql1); // execute()函数可以执行传进来的任意SQL语句 // 执行插入数据的SQL语句 st.execute(sql2); // 释放资源 st.close(); 5.2.PreparedStatement接口: /** * 例子:PreparedStatement接口执行查询表中数据的SQL语句 */ String sql3 = "select * from student"; // 创建一个PreparedStatement对象,同时对传入的SQL语句进行预编译 PreparedStatement ps = conn.prepareStatement(sql3); // PreparedStatement接口中的execute()方法是没有参数的,因为SQL语句在创建对象时已传入并且预编译了 ResultSet result = ps.executeQuery(); while(rs.next()){ // 通过索引来获取查询到的值 int id = rs.getInt(1); String name = rs.getString(2); // 通过列名来获取查询到的值 Date date = rs.getDate("updateTime"); } // 释放资源 ps.close(); 6、关闭连接 用完就要释放所连接的数据库及JDBC资源,关闭与数据库的连接 conn.close(); 上面就是是JDBC编程的基本流程,下面对这个过程中涉及到的一些类与方法做简单介绍: 三、相关的类与方法 1、DriverManager类 ——管理驱动 用于管理一组JDBC驱动程序的基本服务。 官方文档介绍:DriverManager (Java Platform SE 8 ) (langp.wang) 其常用成员方法如下: 返回值 方法体 说明 static Connection getConnection(String url) 用指定的数据库URL来创建连接 static Connection getConnection(String url, Properties info) 用指定的数据库URL和相关信息(用户名、用户密码等属性列表)来创建连接 static Connection getConnection(String url, String user, String password) 用指定的数据库URL、用户名和用户密码来创建连接 static Driver getDriver(String url) 定位在给定URL下的驱动程序。 DriverManager尝试从已注册的JDBC驱动程序集中选择适当的驱动程序。 static void deregisterDriver(Driver driver) 从DriverManager的已注册驱动程序列表中删除指定的驱动程序。 static void println(String message) 将消息输出到当前JDBC日志流。 static void setLoginTimeout(int seconds) 驱动程序尝试连接数据库时将等待的最长时间,以秒为单位。 2、Connection接口 ——建立连接 负责建立与指定数据库的连接。 默认情况下,Connection对象处于自动提交模式,这意味着它在执行每个语句后自动提交更改。 如果禁用了自动提交模式,则必须显式调用方法commit()方法才能提交更改;否则,将不会保存数据库更改。 官方文档介绍: Connection (Java Platform SE 8 ) (langp.wang) 其常用成员方法如下: 返回值 方法体 说明 Statement createStatement() 创建一个Statement对象,用于将SQL语句发送到数据库。 PreparedStatement prepareStatement(String sql) 创建一个PreparedStatement对象,用于将参数化的SQL语句发送到数据库。 void close() 立即释放此Connection对象的数据库和JDBC资源,而不是等待它们自动释放。 void commit() 使自上一次提交/回退以来进行的所有更改永久生效,并释放此Connection对象当前持有的所有数据库锁。 void rollback() 撤销对数据库执行的添加、删除或者修改记录等操作,并释放此Connection对象当前持有的所有数据库锁。 3、Statement接口 ——执行SQL语句 用于执行静态SQL语句并返回其产生的结果的对象。 默认情况下,每个Statement对象只能同时打开一个ResultSet对象。 因此,如果一个ResultSet对象的读取与另一个的读取交错,则每个都必须由不同的Statement对象生成。 如果当前存在打开的语句,Statement接口中的所有执行方法都会隐式关闭该语句的当前ResultSet对象。 官方文档介绍: Statement (Java Platform SE 8 ) (langp.wang) 其常用成员方法如下: 返回值 方法体 说明 Connection getConnection() 检索产生此Statement对象的Connection对象 void close() 立即释放此Statement对象的数据库和JDBC资源,而不是在自动关闭时等待它发生 boolean execute(String sql) 执行给定的SQL语句,该语句可能返回多个结果 ResultSet executeQuery(String sql) 执行给定的SQL语句,该语句返回一个ResultSet对象 int executeUpdate(String sql) 执行给定的SQL语句,该语句可以是INSERT,UPDATE或DELETE语句,也可以是不返回任何内容的SQL语句,例如SQL DDL语句 ResultSet getResultSet() 以ResultSet对象的形式检索当前结果 executeUpdate()、executeQuery()与execute()方法的区别: execute()函数:可以执行所有SQL语句。 当执行查询语句时,返回的boolean值指示查询结果的形式,返回值为true时表示查询结果为ResultSet,反之为false(即认为没有查到);执行其他语句时,如果第一个结果是更新计数或不存在任何结果,则返回false executeUpdate():执行insert、update、delete等不返回任何内容的非查询语句。 executeQuery():用于执行select语句。返回一个ResultSet对象,其中包含由给定查询产生的数据; 永不为空 4、PreparedStatement接口 ——执行SQL语句 表示预编译的SQL语句的对象。是Statement的子接口。 创建PreparedStatement对象时需传入一个SQL语句,该SQL语句已预编译并存储在PreparedStatement对象中。然后可以使用该对象多次有效地执行该语句。 官方文档介绍: PreparedStatement (Java Platform SE 8 ) (langp.wang) 其常用成员方法如下: 返回值 方法体 说明 boolean execute() 在此PreparedStatement对象中执行SQL语句,可以是任何类型的SQL语句 ResultSet executeQuery() 在此PreparedStatement对象中执行SQL查询,并返回查询生成的ResultSet对象 int executeUpdate() 在此PreparedStatement对象中执行SQL语句,该对象必须是SQL数据操作语言(DML)语句,例如INSERT,UPDATE或DELETE; 或不返回任何内容的SQL语句,例如DDL语句 5、ResultSet接口 ——存放查询之后返回的结果 表示数据库结果集的数据表,通常通过执行查询数据库的语句来生成。 ResultSet对象有一个游标,该游标指向其当前数据行。 最初,光标位于第一行之前。next()方法可将光标移动到下一行,当ResultSet对象中没有更多行时它将返回false,因此可以在while循环中使用它来迭代结果集。例如: // 假设rs是前面进行查询操作返回的ResultSet对象 while(rs.next()){ // 输出结果 } 用next()方法可以实现访问每一个数据行,那么如何获取数据行中的每一列数据呢?ResultSet接口提供了用于从当前行中检索列值的getter方法,方法名是get+类型,如getBoolean(),getInt()。 getter方法的参数可以是列的索引值或者列的名称,对应的是用索引或者列名来从当前数据行中检索列值。 通常,使用列索引会更有效。 列从1开始编号。为实现最大的可移植性,应按从左到右的顺序读取每一行中的结果集列,并且每一列只能读取一次。 getter方法用列名检索时传入的列名称不区分大小写。 当多个列具有相同的名称时,将返回第一个匹配列的值。 对于在查询中未明确命名的列,最好使用列的索引。 如果使用了列名,则应注意确保它们唯一地引用了预期的列,这可以通过SQL AS子句来确保。 例如: // 假设rs是前面进行查询操作返回的ResultSet对象 while(rs.next()){ // 使用索引来检索 int id = rs.getInt(1); // 使用列的名称来检索 String name = rs.getString("name"); // 且列名不区分大小写 Date updateTime = rs.getDate("UPDATETIME"); } 官方文档介绍: ResultSet (Java Platform SE 8 ) (langp.wang) 其常用成员方法如下: 返回值 方法体 说明 boolean absolute(int row) 将光标移动到此ResultSet对象中的给定行号 boolean first() 将光标移动到此ResultSet对象的第一行 void beforeFirst() 将光标移动到此ResultSet对象的前面,紧挨着第一行 boolean isFirst() 检索光标是否在此ResultSet对象的第一行上 boolean last() 将光标移动到此ResultSet对象的最后一行 void afterLast() 将光标移动到此ResultSet对象的末尾,紧接在最后一行之后 boolean isLast() 检索光标是否在此ResultSet对象的最后一行 boolean next() 将光标从当前位置向前移动一行 void insertRow() 将插入行的内容插入到此ResultSet对象和数据库中 void updateRow() 使用此ResultSet对象的当前行的新内容更新底层数据库 void deleteRow() 从此ResultSet对象和底层数据库中删除当前行 void update类型(int ColumnIndex,类型 x) 使用给定类型x更新指定列 int get类型(int ColumnIndex) 以Java类型的形式获取此ResultSet的对象的当前行中指定列的值 主要参考资料: 《数据库系统概论(第5版)》 王珊 萨师煊 编著 Java SE 1.8 官方文档
2021年05月24日
1,600 阅读
0 评论
1 点赞
2021-04-14
IDEA添加并配置Tomcat服务器
目录: 一、提前准备 二、创建Java web项目 三、添加Tomcat服务器 四、启动Tomcat服务器 五、其他操作 更改Tomcat默认端口 环境说明: 系统:Win10专业版 JDK版本:1.8 Tomcat版本:8.5.57 开发环境:IDEA 2020.03 Ultimate 一、提前准备 首先,访问Tomcat官网,选择一个版本的Tomcat进行下载,下载完之后解压。本篇博客以Tomcat8.5为例,下载的是windows 64位。下载完之后解压,记住解压完的文件位置,后面导入服务器时要用到。 其次,要保证当前的计算机正确配置了Java环境,win10系统下Java环境的配置请参考:Win10系统配置Java开发环境 二、创建Java web项目 注意:IDEA的Community版本是无法进行Web开发的,Web开发需要Ultimate版本 打开IDEA,先创建一个Java项目。然后在项目名上依次点击右键->”Add Framework Support“,弹出的窗口中勾选“Web Application”选项,点击右下角“OK”即可。 这样创建出来的就是Java web项目了,原来的项目目录会多出来一个“web”文件夹: 三、添加Tomcat服务器 依次点击“File”->“setting”(或者快捷键Ctrl+Alt+s)打开设置界面,然后选择“Build,Execution,Deployment”->“Application Servers”,点击“+”新添加一个应用服务器: 选择的服务器类型为“Tomcat Server”,注意不要选成“TomEE Server”: 在弹出的窗口中选择本地Tomcat的所在目录,IDEA会自动识别出Tomcat的版本,两连“OK”退出 回到主界面,找到菜单栏右边的“Add Configuration”: 点击左上角“+”,在展开的列表中依次选择“Tomcat Server”->“Local”,新建一个本地服务配置。因为前面添加了Tomcat服务器,所以右侧窗口中出现的配置项已自动填好,有需要的可以根据下图说明来改变部分选项: 然后我们需要把之前新建的这个项目放到Tomcat服务器上运行。切换到选项卡“Deployment”,点击左下角“+”,选择“Artifact”,当前项目就被添加上去了,添加完点击“OK”退出。 四、启动Tomcat服务器 如果前面配置没问题的话,现在左下角会出现“Services”窗口选项,在服务器名称上右键->“Run”,Tomcat服务器就启动了。 等待几秒钟服务器完全启动之后,会自动在浏览器中打开项目,如果没有自动打开那就用“localhost:8080”在浏览器中访问项目。 当前由于我们运行的只是空项目,没有对项目做任何更改,所以项目的运行结果会是下面这样: 到这里就配置成功了。 五、其他操作 更改Tomcat默认端口 在主界面找到菜单栏右边的“Tomcat ”,选择“Edit Configurations”: “HTTP port”是默认端口,更改完之后要重启Tomcat服务器才能生效 暂时这些,其他的碰到再添加。
2021年04月14日
1,548 阅读
0 评论
0 点赞
2021-04-07
Win10系统配置Java开发环境
目录: 两句废话 一、安装JDK 二、配置环境变量 三、验证环境是否搭建成功 环境说明: 系统:Win10专业版 Java版本:1.8 两句废话 最近收到了升级Win10 20H2版本的更新消息(别问我为什么2021年才收到2020年的更新包,问就是不知道),之前也听说这是修复Bug的一次更新。所以出于对微软的信任,原来的旧系统我并没有备份,就直接升级了系统,系统升级过程还算顺利。但是,我还是太”轻敌“了,新系统用了几天之后,原来的Bug修没修复还真没感觉出来,能感觉出来的反倒是是几个新的Bug:Win+V打不开剪贴板,运行窗口用notepad打不开记事本,快捷键Shift+Win+S无法打开windows自带的截图功能,这几项Bug暂且还能接受,因为有其他第三方软件能够代替这几个功能。最让我难受的一个Bug就是全屏开始菜单里的图标全成了光秃秃的小方块,没有应用名字,也没有图案logo,每次打开开始菜单都得回忆一下要找的应用的位置,非常麻烦,网上提供的方法也基本上都是治标不治本,用了一周多实在是忍受不了这些Bug,于是忍痛重装了系统。 所以话说回来,更新Win10之前一定要把原来的系统备份一遍!!!!这次经历可真是太长记性了。 重装完系统的确清爽多了,但是写Java时,才想起来新系统的Java环境还没配置,所以把配置Java环境的过程记录下来,方便以后查询(以后谁要让我帮他配Java环境,我就把这篇博客链接扔过去)。 嗯,废话讲完了。 附上Oracle官方文档中安装Java环境的相关链接:JDK Installation for Microsoft Windows (oracle.com) 一、安装JDK 首先下载JDK安装包。 Java 官网:Oracle 甲骨文中国 | 集成的云应用和平台服务 JDK 最新版本下载:Java Downloads | Oracle 旧版本 JDK 下载:Java Archive | Oracle 选择一个Java版本之后,选择“Windows x64”版本进行下载。 由于下载 JDK 旧版本需要登录 Oracle 帐号,随便用临时邮箱注册了一个账号,用这个就行: 帐号:linshi@linshiyouxiang.net 密码:Youxiang123@ 本篇博客以JDK 8(也称为JDK 1.8)作为示例来说明。 下载好之后打开安装,安装的是JDK和JRE两部分。安装时直接一路点击“下一步”,安装注意一下安装位置,后面要用。 二、配置环境变量 “计算机”图标上点击右键->属性->高级系统设置(win10 20H2需要在属性窗口的后面才能找到高级系统设置),在高级系统设置窗口的右下角点击“环境变量”。 “环境变量”分为两部分,一个是“用户变量”,这里面配置的环境变量只适用于当前计算机用户,另一个是“系统变量”,设置的环境变量适用于这台计算机上的所有用户。具体设置成哪种环境变量看个人习惯。 添加如下两条环境变量: 环境变量名称 环境变量值 JAVA_HOME C:\Program Files\Java\jdk1.8.0_221 Path %JAVA_HOME%\bin JAVA_HOME的值是JDK的安装路径,如果在上一步安装的时候没有更改安装路径的话,则JDK的默认安装路径为:“C:\Program Files\Java\jdk1.8.0_221 ”,因为版本号的问题,JDK的安装文件夹名称可能会有些许差别,请根据实际情况写。 其实第一个环境变量的名称并不是固定的,在其他的配置Java环境变量的教程中名称也可能不同。这个只是习惯而已,只要保证环境变量值没什么问题即可。 这两条添加完之后,两连“确定”完成配置。 三、验证环境是否搭建成功 使用快捷键Win+R打开运行窗口,输入“cmd”,然后回车打开命令行界面,使用如下命令查看当前系统的Java版本: java -version 结果如下: 结果正确显示出Java的版本信息时,说明Java环境配置成功。
2021年04月07日
2,174 阅读
0 评论
0 点赞
1
2