springboot笔记
1. 使用mybatis-plus
-
添加MyBatis Plus依赖项:在您的
pom.xml
文件中添加以下依赖项:<dependencies> <!-- MyBatis Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>最新版本</version> </dependency> <!-- 其他依赖项... --> </dependencies>
-
配置数据库连接:在
application.properties
或application.yml
文件中添加数据库连接的配置信息,例如:spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.jdbc.Driver
-
创建实体类:创建与数据库表对应的实体类。确保使用
@TableName
注解标记实体类对应的表名,以便MyBatis Plus能够正确地映射。import com.baomidou.mybatisplus.annotation.TableName; @TableName("user") public class User { private Long id; private String name; private Integer age; // 其他属性和方法... }
-
创建Mapper接口:创建与实体类对应的Mapper接口,并继承
BaseMapper
接口。MyBatis Plus将自动为您生成通用的CRUD方法。import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface UserMapper extends BaseMapper<User> { // 可以添加额外的自定义方法... }
-
配置Mapper扫描:在Spring Boot的配置类中,使用
@MapperScan
注解指定Mapper接口所在的包,以便自动扫描并注册Mapper Bean。import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Configuration; @Configuration @MapperScan("com.example.mapper") public class MyBatisConfig { // 其他配置... }
-
使用Mapper接口:在您的服务类或控制器中,通过依赖注入的方式使用Mapper接口,并调用相应的方法进行数据库操作。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserMapper userMapper; public User getUserById(Long id) { return userMapper.selectById(id); } // 其他方法... }
2. 使用redis
-
添加Redis依赖项:在您的
pom.xml
文件中添加以下依赖项:<dependencies> <!-- Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 其他依赖项... --> </dependencies>
-
配置Redis连接:在
application.properties
或application.yml
文件中添加Redis连接的配置信息,例如:spring.redis.host=localhost spring.redis.port=6379 spring.redis.password=your_password
-
创建Redis配置类:在Spring Boot的配置类中,创建一个
RedisConfig
类,并添加@Configuration
和@EnableCaching
注解,@EnableCaching
注解用于启用Spring的缓存支持。import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Configuration; @Configuration @EnableCaching public class RedisConfig { // 其他配置... }
-
使用Redis缓存:在您的服务类或控制器中,使用
@Cacheable
、@CachePut
等注解来标记需要缓存的方法,@Cacheable
注解表示方法的结果将被缓存起来,@CachePut
注解表示方法的结果将被更新到缓存中。import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service public class UserService { @Cacheable(value = "users", key = "#id") public User getUserById(Long id) { // 从数据库或其他数据源获取用户信息 return userRepository.findById(id); } @CachePut(value = "users", key = "#user.id") public User saveUser(User user) { // 保存用户信息到数据库或其他数据源 return userRepository.save(user); } // 其他方法... }
-
使用RedisTemplate:如果需要更复杂的Redis操作,可以使用
RedisTemplate
进行操作,通过redisTemplate
对象调用opsForValue()
方法来执行Redis操作。import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private RedisTemplate<String, Object> redisTemplate; public void setValue(String key, Object value) { redisTemplate.opsForValue().set(key, value); } public Object getValue(String key) { return redisTemplate.opsForValue().get(key); } // 其他方法... }
3. 使用AOP
-
添加AOP依赖项:在您的
pom.xml
文件中添加以下依赖项:<dependencies> <!-- AOP --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- 其他依赖项... --> </dependencies>
-
创建一个切面类:创建一个类,使用
@Aspect
注解来标记它作为切面类。在切面类中,您可以定义各种通知(Before、After、Around等)和切入点表达式。import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.demo.service.*.*(..))") public void beforeAdvice() { System.out.println("Before method execution"); } }
在上面的示例中,创建了一个切面类
LoggingAspect
,使用@Before
注解来定义一个前置通知。execution(* com.example.demo.service.*.*(..))
是切入点表达式,表示匹配com.example.demo.service
包中的所有方法。 -
启用AOP:在Spring Boot的配置类上添加
@EnableAspectJAutoProxy
注解来启用AOP。import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy public class AppConfig { // 其他配置... }
-
切入点表达式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
其中,各个部分的含义如下:
modifiers-pattern:表示方法的修饰符模式,如public、private、protected等,默认为*匹配任意修饰符。 ret-type-pattern:表示方法的返回类型模式,如void、int、java.lang.String等,默认为*匹配任意返回类型。 declaring-type-pattern:表示方法所在类的全限定名模式,如com.example.demo.service.*表示匹配com.example.demo.service包中的所有类,默认为*匹配任意类。 name-pattern:表示方法名模式,如save*表示匹配以save开头的方法名,默认为*匹配任意方法名。 param-pattern:表示方法参数模式,如(..)表示匹配任意参数列表,(java.lang.String)表示匹配只有一个String类型参数的方法。 throws-pattern:表示方法抛出异常类型模式,如java.lang.Exception表示匹配抛出Exception异常的方法,默认为*匹配任意异常类型。
下面是一些示例使用
execution
的切入点表达式:execution(public * com.example.demo.service.*.*(..)): 匹配com.example.demo.service包中所有公共方法。 execution(* com.example.demo.service.UserService.save*(..)): 匹配com.example.demo.service.UserService类中以save开头的所有方法。 execution(* com.example.demo.service.UserService.*(..)): 匹配com.example.demo.service.UserService类中的所有方法。 execution(* com.example.demo.service.UserService.*()): 匹配com.example.demo.service.UserService类中不带任何参数的方法。 execution(* com.example.demo.service.UserService.*(java.lang.String, ..)): 匹配com.example.demo.service.UserService类中第一个参数为String类型的方法。 execution(* com.example.demo.service.*.*(..) throws java.lang.Exception): 匹配所有抛出Exception异常的方法。
4. 解决跨域问题
-
添加CORS依赖项:在您的
pom.xml
文件中添加以下依赖项:<dependencies> <!-- CORS --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 其他依赖项... --> </dependencies>
-
配置CORS:在Spring Boot的配置类中,添加
WebMvcConfigurer
的实现类,并重写addCorsMappings
方法来配置CORS。import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }
在上面的示例中,允许所有来源(
allowedOrigins("*")
),允许的HTTP方法(allowedMethods("GET", "POST", "PUT", "DELETE")
),允许所有请求头(allowedHeaders("*")
),启用跨域资源共享凭证(allowCredentials(true)
),并设置预检请求的最大缓存时间(maxAge(3600)
)。
5. 域对象共享数据
-
使用HttpServletRequest对象:
@Controller public class MyController { @RequestMapping("/storeData") public String storeData(HttpServletRequest request) { request.setAttribute("myData", "Hello, World!"); return "redirect:/getData"; } @RequestMapping("/getData") public String getData(HttpServletRequest request, Model model) { String data = (String) request.getAttribute("myData"); model.addAttribute("data", data); return "myPage"; } }
-
使用@SessionAttributes注解:
@Controller @SessionAttributes("myData") public class MyController { @RequestMapping("/storeData") public String storeData(Model model) { model.addAttribute("myData", "Hello, World!"); return "redirect:/getData"; } @RequestMapping("/getData") public String getData(@ModelAttribute("myData") String data, Model model) { model.addAttribute("data", data); return "myPage"; } }
-
使用HttpSession对象:
@Controller public class MyController { @RequestMapping("/storeData") public String storeData(HttpSession session) { session.setAttribute("myData", "Hello, World!"); return "redirect:/getData"; } @RequestMapping("/getData") public String getData(HttpSession session, Model model) { String data = (String) session.getAttribute("myData"); model.addAttribute("data", data); return "myPage"; } }
-
使用@ModelAttribute注解:
@Controller public class MyController { @ModelAttribute("myData") public String getMyData() { return "Hello, World!"; } @RequestMapping("/getData") public String getData(@ModelAttribute("myData") String data, Model model) { model.addAttribute("data", data); return "myPage"; } }
-
使用@SessionScoped注解:
@Component @SessionScoped public class MySessionBean implements Serializable { private String myData; public String getMyData() { return myData; } public void setMyData(String myData) { this.myData = myData; } } @Controller public class MyController { @Autowired private MySessionBean sessionBean; @RequestMapping("/storeData") public String storeData() { sessionBean.setMyData("Hello, World!"); return "redirect:/getData"; } @RequestMapping("/getData") public String getData(Model model) { String data = sessionBean.getMyData(); model.addAttribute("data", data); return "myPage"; } }
-
使用数据库或缓存:
@Controller public class MyController { @Autowired private MyDataRepository dataRepository; @RequestMapping("/storeData") public String storeData() { MyData myData = new MyData("Hello, World!"); dataRepository.save(myData); return "redirect:/getData"; } @RequestMapping("/getData") public String getData(Model model) { MyData myData = dataRepository.getMyData(); model.addAttribute("data", myData.getData()); return "myPage"; } }
-
下表对比了上述6种Spring Boot中域对象共享数据的方式的优缺点及使用主义事项。
方式 优点 缺点 使用注意事项 HttpServletRequest对象 - 简单,直接使用Servlet API - 需要显式地在控制器方法中传递HttpServletRequest对象
- 没有类型安全性- 需要注意数据存储和获取的位置,避免覆盖或错误访问数据
- 需要处理异常情况,如请求未包含数据时的处理@SessionAttributes注解 - 使用简单,通过注解指定要共享的模型属性
- 数据存储在会话域中,可以在多个请求处理方法中共享- 只能在控制器类级别上共享数据,无法在不同控制器之间共享
- 会话结束后,数据将被清除
- 不适用于非Web环境的应用程序(如REST API)- 将需要共享的数据定义为模型属性,并使用@ModelAttribute访问和修改数据
- 需要注意会话的生命周期,避免数据过早清除或过长保留HttpSession对象 - 使用简单,直接使用HttpSession对象 - 需要显式地在控制器方法中传递HttpSession对象
- 没有类型安全性- 需要注意数据存储和获取的位置,避免覆盖或错误访问数据
- 需要处理异常情况,如会话过期或不存在时的处理@ModelAttribute注解 - 使用简单,通过注解定义模型属性,并自动存储和获取数据 - 只能在同一控制器类中共享数据
- 无法在不同的请求处理方法之间共享数据- 将需要共享的数据定义为模型属性,并使用@ModelAttribute访问和修改数据
- 需要注意模型属性的作用域,避免数据过早清除或过长保留@SessionScoped注解 - 数据存储在会话级别的Spring Bean中,可以在多个控制器和服务之间共享 - 需要在会话bean中管理共享数据的状态
- 需要手动创建和配置会话bean- 将共享的数据存储在会话bean中,并通过依赖注入在不同的控制器和服务中使用数据
- 需要注意会话bean的生命周期,避免数据过早销毁使用数据库或缓存 - 数据存储在持久化存储或缓存中,可以在不同的应用程序实例和会话之间共享 - 需要引入数据库或缓存的依赖
- 需要定义数据模型和访问方法
- 需要处理并发访问和一致性问题- 将共享的数据存储在数据库或缓存中,并通过依赖注入在不同的控制器和服务中使用数据
- 需要注意数据访问的性能和并发访问的安全性
6. 统一异常处理
-
创建一个自定义的
ResourceNotFoundException
异常类:public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException(String message) { super(message); } }
-
在控制器中抛出该异常
@RestController public class UserController { @GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { User user = userRepository.findById(id); if (user == null) { throw new ResourceNotFoundException("User not found"); } return user; } }
-
在全局异常处理器中处理
ResourceNotFoundException
异常:@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) { String errorMessage = "资源不存在"; return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorMessage); } @ExceptionHandler(Exception.class) public ResponseEntity<String> handleException(Exception ex) { String errorMessage = "发生了一个错误"; return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage); } }
在上面的代码中,在
GlobalExceptionHandler
类中添加了一个新的方法handleResourceNotFoundException
,用于处理ResourceNotFoundException
异常。在该方法中,返回了一个自定义的错误信息,并设置了响应的状态码为 404(NOT_FOUND)。这样,当用户请求一个不存在的用户资源时,将会抛出
ResourceNotFoundException
异常,并由全局异常处理器捕获并处理,返回自定义的错误信息。注意事项:
- 可以根据具体的业务需求,自定义不同类型的异常,并在全局异常处理器中处理。
- 全局异常处理器可以处理多个不同类型的异常,可以根据实际需要添加多个异常处理方法。
7. 自定义过滤器
-
创建一个实现
javax.servlet.Filter
接口的自定义过滤器类。public class CustomFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化方法 } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 在这里编写对请求的处理逻辑 // 继续调用过滤器链 chain.doFilter(request, response); } @Override public void destroy() { // 销毁方法 } }
-
创建一个配置类,并在该类中注册并配置过滤器。
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean<CustomFilter> customFilterRegistration() { FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CustomFilter()); registrationBean.addUrlPatterns("/api/*"); // 指定过滤路径 registrationBean.setOrder(1); // 设置过滤器的顺序 return registrationBean; } }
在上述示例中,使用
FilterRegistrationBean
注册了CustomFilter
过滤器,并使用addUrlPatterns
方法指定了过滤路径为/api/*
。还使用setOrder
方法设置了过滤器的顺序为 1,这意味着它将在其他过滤器之前被执行。 -
在您的 Spring Boot 应用程序的入口类上添加
@ServletComponentScan
注解,以启用对Filter
的扫描。@SpringBootApplication @ServletComponentScan public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
8. 自定义拦截器
-
创建实现
HandlerInterceptor
接口的自定义拦截器类。public class CustomInterceptor1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在请求处理之前执行的逻辑 return true; // 返回 true 表示继续执行后续的拦截器和请求处理方法 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 请求处理之后但未渲染视图时执行的逻辑 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 请求处理完成并且视图已渲染之后执行的逻辑 } } public class CustomInterceptor2 implements HandlerInterceptor { // ... 自定义拦截器2的实现代码 ... }
-
创建一个配置类,实现
WebMvcConfigurer
接口,并重写addInterceptors
方法进行拦截器的配置。@Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CustomInterceptor1()).addPathPatterns("/api/*"); // 指定拦截路径 registry.addInterceptor(new CustomInterceptor2()).addPathPatterns("/admin/*"); // 指定拦截路径 } }
在上述示例中,分别创建了
CustomInterceptor1
和CustomInterceptor2
拦截器,并使用addPathPatterns
方法分别指定了它们的拦截路径为/api/*
和/admin/*
。