电子说
在使用spring的过程中,我们有没有发现它的扩展能力很强呢?由于这个优势的存在,使得spring具有很强的包容性,所以很多第三方应用或者框架可以很容易的投入到spring的怀抱中。今天我们主要来学习Spring中很常用的11个扩展点,你用过几个呢?
如果接口中接收参数的实体对象中,有一个字段类型为Date,但实际传递的参数是字符串类型:2022-12-15 10:20:15,该如何处理?
Spring提供了一个扩展点,类型转换器Type Converter
,具体分为3类:
Converter
: 将类型 S 的对象转换为类型 T 的对象ConverterFactory
: 将 S 类型对象转换为 R 类型或其子类对象GenericConverter
:它支持多种源和目标类型的转换,还提供了源和目标类型的上下文。此上下文允许您根据注释或属性信息执行类型转换。还是不明白的话,我们举个例子吧。
@Data
public class User {
private Long id;
private String name;
private Date registerDate;
}
Converter
接口public class DateConverter implements Converter
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DateConverter());
}
}
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/save")
public String save(@RequestBody User user) {
return "success";
}
}
请求接口时,前端传入的日期字符串,会自动转换成Date类型。
在我们日常开发中,经常需要从Spring容器中获取bean,但是你知道如何获取Spring容器对象吗?
@Service
public class PersonService implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public void add() {
Person person = (Person) beanFactory.getBean("person");
}
}
实现BeanFactoryAware接口,然后重写setBeanFactory方法,可以从方法中获取spring容器对象。
@Service
public class PersonService2 implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void add() {
Person person = (Person) applicationContext.getBean("person");
}
}
实现ApplicationContextAware
接口,然后重写setApplicationContext
方法,也可以通过该方法获取spring容器对象。
@Service
public class PersonService3 implements ApplicationListener<ContextRefreshedEvent> {
private ApplicationContext applicationContext;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
applicationContext = event.getApplicationContext();
}
public void add() {
Person person = (Person) applicationContext.getBean("person");
}
}
以往我们在开发界面的时候,如果出现异常,要给用户更友好的提示,例如:
@RequestMapping("/test")
@RestController
public class TestController {
@GetMapping("/add")
public String add() {
int a = 10 / 0;
return "su";
}
}
如果不对请求添加接口结果做任何处理,会直接报错:
用户可以直接看到错误信息吗?
这种交互给用户带来的体验非常差。为了解决这个问题,我们通常在接口中捕获异常:
@GetMapping("/add")
public String add() {
String result = "success";
try {
int a = 10 / 0;
} catch (Exception e) {
result = "error";
}
return result;
}
界面修改后,出现异常时会提示:“数据异常”,更加人性化。
看起来不错,但是有一个问题。
如果只是一个接口还好,但是如果项目中有成百上千个接口,还得加异常捕获代码吗?
答案是否定的,这就是全局异常处理派上用场的地方:RestControllerAdvice
。
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
if (e instanceof ArithmeticException) {
return "data error";
}
if (e instanceof Exception) {
return "service error";
}
retur null;
}
}
方法中处理异常只需要handleException
,在业务接口中就可以安心使用,不再需要捕获异常(统一有人处理)。
Spring MVC拦截器,它可以获得HttpServletRequest
和HttpServletResponse
等web对象实例。
Spring MVC拦截器的顶层接口是HandlerInterceptor
,它包含三个方法:
preHandle
在目标方法执行之前执行postHandle
afterCompletion
在请求完成时执行为了方便,我们一般继承HandlerInterceptorAdapter
,它实现了HandlerInterceptor
。
如果有授权鉴权、日志、统计等场景,可以使用该拦截器,我们来演示下吧。
HandlerInterceptorAdapter
:public class AuthInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestUrl = request.getRequestURI();
if (checkAuth(requestUrl)) {
return true;
}
return false;
}
private boolean checkAuth(String requestUrl) {
return true;
}
}
@Configuration
public class WebAuthConfig extends WebMvcConfigurerAdapter {
@Bean
public AuthInterceptor getAuthInterceptor() {
return new AuthInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor());
}
}
有时我们需要在某个配置类中引入其他的类,引入的类也加入到Spring容器中。这时候可以使用注解@Import
来完成这个功能。
如果你查看它的源代码,你会发现导入的类支持三种不同的类型。
但是我觉得最好把普通类的配置类和@Configuration
注解分开解释,所以列出了四种不同的类型:
全部0条评论
快来发表一下你的评论吧 !