首页
碎碎念
东邻西舍
本站信息
前来吐槽
统计
Search
1
openwrt系统上安装第三方插件
26,758 阅读
2
ubuntu下zerotier的基本使用教程
13,578 阅读
3
给小米R3G更换系统:从padavan刷成openwrt
12,848 阅读
4
openwrt使用第一步:设置上网拨号
10,741 阅读
5
openwrt无线中继功能:实现不插网线就能上网
9,519 阅读
学习点滴
Java
Web前端
Linux
踩坑实录
折腾搞机
关于建站
只言片语
登录
Search
标签搜索
Linux
建站
Java
踩坑实录
Ubuntu
MySQL
折腾搞机
HTML
CSS
MyBatis
Spring
SQL
Nginx
路由器
树莓派
OpenWrt
Maven
Git
Win10
只言片语
知识分子没文化
累计撰写
83
篇文章
累计收到
152
条评论
首页
栏目
学习点滴
Java
Web前端
Linux
踩坑实录
折腾搞机
关于建站
只言片语
页面
碎碎念
东邻西舍
本站信息
前来吐槽
统计
搜索到
50
篇与
的结果
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,049 阅读
0 评论
3 点赞
2021-11-19
【代码摘录】HTML+CSS实现下拉菜单
目录: 一、演示效果 二、源代码 1.HTML代码 2.CSS 在B站上看到一个up主写的一段下拉菜单代码,实现效果还挺好看的,遂进行小改之后拿来收藏,以供日后使用。 源代码出自:B站up主 山羊の前端小窝 视频链接:https://www.bilibili.com/video/BV1S44y147oV 一、演示效果 演示如下,鼠标悬浮即可查看效果: 二、源代码 1.HTML代码 <body> <ul class="shell"> <li class="button"> <span>消息</span> <ul> <li><a href="" target="_blank">回复我的</a></li> <li><a href="" target="_blank">收到的赞</a></li> <li><a href="" target="_blank">我的消息</a></li> </ul> </li> <li class="button"> <span><a href="" target="_blank">动态</a></span> </li> <li class="portrait"> <ul class="information"> <li>知识分子没文化</li> <li><a href="https://www.wlplove.com" target="_blank">博客</a></li> </ul> </li> <li class="button"> <span>收藏夹</span> <ul> <li><a href="" target="_blank">默认收藏夹</a></li> <li><a href="" target="_blank">计算机编程</a></li> <li><a href="" target="_blank">有点意思</a></li> <li><a href="" target="_blank">说的不错</a></li> </ul> </li> <li class="button"> <span>投稿</span> <ul> <li><a href="" target="_blank">专栏投稿</a></li> <li><a href="" target="_blank">音频投稿</a></li> <li><a href="" target="_blank">贴纸投稿</a></li> <li><a href="" target="_blank">视频投稿</a></li> <li><a href="" target="_blank">投稿管理</a></li> </ul> </li> </ul> </body> 2.CSS * { margin: 0; padding: 0; list-style: none; font-size: 20px; color: #f4f1de; } .shell { display: flex; justify-content: center; margin-top:50px; } .button, .portrait { background-color: #50536e; width: 170px; height: 65px; text-align: center; line-height: 65px; transition: 0.3s; /* 指定浏览网页时鼠标指针的形状 */ cursor: pointer; } .portrait::before { content: ''; display: block; width: 100px; height: 100px; border-radius: 50%; transform: translate(30px, -30px); background-image: url("https://image.wlplove.com/static/img/icon/headpic.png"); background-size: cover; border: 10px solid #fff; } .information { width: 220px; background-color: #e07a5f; transform: translate(-20px, -200px); border-radius: 10px; padding: 20px 0; line-height: 0; height: 0; transition: 0.3s; /* opacity属性指定了一个元素的不透明度,其取值从0-1。*/ /* 在0时会完全看不见,1表示完全可见 */ opacity: 0; } .button:hover { background-color: #d15a39; } .button li:hover { background-color: #ffb29d; } .button ul li { height: 0; transition: 0.2s; opacity: 0; transform: translateY(-65px); background-color: #e07a5f; } .button:hover li { height: 65px; opacity: 1; transform: translateY(0); } .portrait:hover .information { opacity: 1; line-height: 65px; transform: translate(-20px, -10px); height: auto; } a{ text-decoration: none; }
2021年11月19日
1,629 阅读
0 评论
0 点赞
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,256 阅读
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日
444 阅读
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,202 阅读
0 评论
1 点赞
1
2
3
...
10