从零开始springmvc|20240304

  1. 原始配置

《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修饰,就是使用一次转换器;没有修饰,就是遍历所有字段使用转换器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值