-
原始配置
《web.xml》
<servlet>
<servlet-name>mySpringmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- <init-param>-->
<!-- <param-name>contextConfigLocation</param-name>-->
<!-- <param-value>classpath:xxx.xml</param-value>-->
<!-- </init-param>-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mySpringmvc</servlet-name>
<url-pattern>/</url-pattern>
<!-- /匹配所有请求,不包含jsp
/*匹配所有请求,包含jsp -->
</servlet-mapping>
《spring-mvc》
<context:component-scan base-package="com.test.mvc"/>
1.1默认使用的handlerMapping ,从dispatcherservlet.properties中获 取。
1.2默认使用的handlerAdapter
HandlerMapping组件的作用解析一个个Request请求,并找到相应处理这个Request的Handler。Handler一般可以理解为Controller控制器里的一个方法。
HandlerMapping组件主要做了两件事件。
1. 在组件初始化时,会把Request请求和对应的Handler进行注册,其实就是把Request和对应的Handler以键值对的形式存在一个map中。
2. 解析一个个Request请求,在注册的map中找相应的handler。
2、使用<mvc:annotation-driven />
注册:RequestMappingHandlerMapping,RequestMappingHandlerAdapter
2.1、 HttpMessageConverter,负责将请求信息转化为对象,将对象输出为响应信息。由RequestMappingHandlerAdapter使用
默认的实现类:
2.1.1、如何使用:添加注解@RequestBody和@ResponseBody后,会使用RequestResponseBodyMethodProcessor
在RequestResponseBodyMethodProcessor里使用HttpMessageConverter。在创建默认HandlerMethodArgumentResolver时,将
httpMessageConverter加入RequestResponseBodyMethodProcessor。
2.1.2、如何在httpMessageConverter中加入解析json
在原有HttpMessageConverter的基础上增加
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="prettyPrint" value="true" />
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
需要添加jar包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
2.1.3、注解@JsonFormat(pattern="yyyyMMdd", timezone = "GMT+8")
String stuJson = "{\"nowDate\":\"20200216\",\"name\":\"zhangsan\"}";
ObjectMapper objectMapper = new ObjectMapper();
Student student = objectMapper.readValue(stuJson, Student.class);
Student{nowDate=Sun Feb 16 00:00:00 CST 2020, name='zhangsan', sex='null', age=null, id=null}
3、conversionService是spring类型转换体系的核心接口,加上<mvc:annotation-driven>注解后,相当于默认添加了 FormattingConversionServiceFactoryBean
if (element.hasAttribute("conversion-service")) {
conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
} else {
RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
3.1、如何自定义类型转换器(convert在原有的基础上增加)
//1、新增转换类器
public class StringToStudent implements Converter<String, Student> {
public Student convert(String s) {
String[] stu = s.split(";");
Student student = new Student();
student.setName(stu[0]);
student.setSex(stu[1]);
student.setAge(Integer.valueOf(stu[2]));
return student;
}
}
//2、mvc xml配置文件
<bean id="myConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.htsc.convert.StringToStudent"/>
</set>
</property>
</bean>
//3、将自定义的覆盖默认的Formatting...
<mvc:annotation-driven conversion-service="myConversionService">
3.2、测试 http://localhost:8080/say?s=zhangsan;man;13 POST
4、数据格式化
===================2023、6、20
@ControllerAdvice
本质也是@Component。加了@ControllerAdvice的类为那些声明了(@ExceptionHandler、@InitBinder 或 @ModelAttribute注解修饰的)方法的类而提供的
专业化的@Component , 以供多个 Controller类所共享。
@ExceptionHandler注解标注的方法:用于捕获Controller中抛出的不同类型的异常,从而达到异常全局处理的目的;
@InitBinder注解标注的方法:用于请求中注册自定义参数的解析,从而达到自定义请求参数格式的目的;
@ModelAttribute注解标注的方法:表示此方法会在执行目标Controller方法之前执行。
这三个注解都可以在普通的Controller类上使用,ControllerAdvice只是作用范围可以自定义(默认全部)
也可以通过指定注解来匹配,比如我自定了一个 @CustomAnnotation 注解,我想匹配所有被这个注解修饰的 Controller, 可以这么写:@ControllerAdvice(annotations={CustomAnnotation.class})
参考博客:(576条消息) @ControllerAdvice 的介绍及三种用法_nsnsttn的博客-CSDN博客
2023/6/21
参数里有HttpServletResponse,mvc会使用参数解析器:ServletResponseMethodArgumentResolver
public boolean supportsParameter(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
return (ServletResponse.class.isAssignableFrom(paramType) ||
OutputStream.class.isAssignableFrom(paramType) ||
Writer.class.isAssignableFrom(paramType));
}
参数有多个,就可能使用多个不一样的参数解析器一个个解析参数。再通过反射调用方法。
参数里有@RequesrBody,mvc会使用RequestResponseBodyMethodProcessor:不走mvc的试图解析流程,跳不到html
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
返回参数是String,且没有@ResponseBody注解,使用返回值解析器ViewNameMethodReturnValueHandler
public boolean supportsReturnType(MethodParameter returnType) {
Class<?> paramType = returnType.getParameterType();
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
}
1、返回void,使用@Controller,没有@ResponseBody,跟使用@ResponseBody,返回对象一样的效果
@GetMapping("/json")
public void json(HttpServletResponse resp) throws IOException {
resp.setContentType("application/json");
resp.getWriter().println("{\"aaa\":\"111\"}");
System.out.println("111");
}
2.1、返回void,通过请求转发页面 ,静态页面需要放在static目录下,这样用户可以通过两种方式获取:直接访问,用户可以访问到无权访问的页面(templates目录下的静态资源不能直接访问);通过controller跳转
@GetMapping("/getRequestDispatcher")
public void getRequestDispatcher(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/success.jsp").forward(request,response);
}
2.2、返回String,Foward转发
@GetMapping("/forward")
public String forward() {
return "forward:/success.jsp";
}
2.3、
@GetMapping("/html")
public String html() {
return "/success.jsp";
}
3.1、重定向
@GetMapping("/redirect")
public String redirect() {
return "redirect:/success.jsp";
}
3.2、
@GetMapping("/resp_redirect")
public void resp_redirect(HttpServletResponse resp) throws IOException {
resp.sendRedirect("/success.jsp");
return;
}
跳转返回的字符串前面必须带/
4、试图解析器
spring:
mvc:
view:
prefix: /
suffix: .jsp
@GetMapping("/view")
public String view() {
return "success";
}
参考:SpringMVC 方法三种类型返回值总结,你用过几种?
=============2023-12-14
ServletModelAttributeMethodProcessor 当参数是对象,且没有注解时,使用这个参数处理器!
@InitBinder注解,可以放在当前controller,也可以放在公共地方@controllerAdvice
ServletModelAttributeMethodProcessor可以让这个注解生效
@RestControllerAdvice
====2024-03-04===============
springboot @JsonFormat注解详解
是jackson中定义的一个时间格式化注解,作用于date类型的属性字段上,
1、接收前端传来的字符串格式的字段,可配置对应格式的@JsonFormat格式转换成date类型,格式不一样会报错;
2、用于指定返回日期类型数据时的时间格式;
3、需要引入jackson的依赖
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.6</version>
</dependency>
4、@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
5、jackson默认的日期反序列化格式"yyyy-MM-dd’T’HH:mm:ss.SSSX"
6、可同时约束请求和响应;只能用在实体上,不能用在方法上;需要结合@RequestBody
@DateTimeFormat
1、即可用于方法,也可用于类的属性;
2、只能处理非json数据格式的字符串(如url-String格式、Form-Data格式)
3、只是解析日期字符串转为Date类型,转换后的日期格式并不会受到@DateTimeFormat
注解中pattern属性的约束。
=======20240313======
mvc内置的类型转换器
1、StringToCollectionConverter,","分割成list;
比如请求 timeCost/bbb?sss=2023/12/12&li=1,2,3,4
2、将请求的string转换成domain里的boolean:StringToBooleanConverter
接口有多个参数
会调用多个HandlerMethodArgumentResolver
b会使用ServletModelAttributeMethodProcessor ;
a1会使用RequestParamMethodArgumentResolver:
RequestParamMethodArgumentResolver除了能处理@RequestParam注解外,还可以处理@RequestPart注解:
当处理@RequestParam注解时,需在某些条件成立的情况下才会使用此类进行解析:
① 方法参数由@RequestParam注解注释。
② 方法参数若是Map类型时,@RequestParam的name属性不能为空。
③ 方法参数若不是Map类型时,都可以处理。
当处理@RequestPart注解时,需在某些条件成立的情况下才会使用此类进行解析:
① 方法参数不可由@RequestPart注解注释。
② 方法参数类型为org.springframework.web.multipart.MultipartFile、org.springframework.web.multipart.MultipartFile集合、org.springframework.web.multipart.MultipartFile数组、javax.servlet.http.Part、javax.servlet.http.Part集合或javax.servlet.http.Part数组。
③ 一个简单类型的方法参数,包括:boolean、byte、char、short、int、long、float、double、Enum.class、CharSequence.class、Number.class、Date.class、URI.class、URL.class、Locale.class或Class.class。
有了@RequestBody貌似不会受类型转换器的影响!?
自定义转换器
1、直接加入spring管理就行了。因为在WebMvcAutoConfiguration里,有bean:WebMvcAutoConfigurationAdapter implements WebMvcConfigurer的方法,直接添加spring里的converter对象。
@Override
public void addFormatters(FormatterRegistry registry) {
ApplicationConversionService.addBeans(registry, this.beanFactory);
}
public static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {
Set<Object> beans = new LinkedHashSet();
beans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values());
beans.addAll(beanFactory.getBeansOfType(Converter.class).values());
beans.addAll(beanFactory.getBeansOfType(Printer.class).values());
beans.addAll(beanFactory.getBeansOfType(Parser.class).values());
Iterator var3 = beans.iterator();
while(var3.hasNext()) {
Object bean = var3.next();
if (bean instanceof GenericConverter) {
registry.addConverter((GenericConverter)bean);
} else if (bean instanceof Converter) {
registry.addConverter((Converter)bean);
} else if (bean instanceof Formatter) {
registry.addFormatter((Formatter)bean);
} else if (bean instanceof Printer) {
registry.addPrinter((Printer)bean);
} else if (bean instanceof Parser) {
registry.addParser((Parser)bean);
}
}
}
@Component
public class DataConverter implements Converter<String, PageDomain> {
@Override
public PageDomain convert(String source) {
String[] split = source.split(",");
PageDomain pageDomain = new PageDomain();
pageDomain.setIsAsc(split[0]);
pageDomain.setPageNum(Integer.valueOf(split[1]));
pageDomain.setPageSize(Integer.valueOf(split[2]));
return pageDomain;
}
}
2、接口写法:这里需要@RequestParam,使用RequestParamMethodArgumentResolver
@GetMapping("/bbb")
public R<Boolean> bbb(@RequestParam("b") PageDomain b,Date a1) {
return R.ok();
}
3、请求方式:
timeCost/bbb?b=aaa,3,4&a1=2024/12/12
4、感觉这个PageDomain,使用@RequestParam修饰,就是使用一次转换器;没有修饰,就是遍历所有字段使用转换器。