SpringMvc学习日记

一、域对象传值

1.1、Request域对象

有多种方式

    // Servlet原生Api方式
    @RequestMapping("/testRequestByServletApi")
    public String testRequestByServletApi(HttpServletRequest request) {
        request.setAttribute("testRequest", "hello, Servlet api");
        return "success";
    }

    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView() {
        ModelAndView view = new ModelAndView();
        view.addObject("testRequest", "hello, ModelAndView");
        view.setViewName("success");
        return view;
    }

    @RequestMapping("/testModel")
    public String testModel(Model model) {
        model.addAttribute("testRequest", "hello, Model");
        return "success";
    }

    @RequestMapping("/testMap")
    public String testModel(Map<String, Object> map) {
        map.put("testRequest", "hello, Model");
        return "success";
    }

    @RequestMapping("/testModelMap")
    public String testModel(ModelMap modelMap) {
        modelMap.addAttribute("testRequest", "hello, ModelMap");
        return "success";
    }

1.2、Session域对象

对于session域对象,直接使用原生的ServletApi比较方便

    @RequestMapping("/testSession")
    public String testModel(HttpSession session) {
        session.setAttribute("testRequest", "hello, session");
        return "success";
    }

二、视图解析器

InternalResourceView:用于转发

RedirectView:用于重定向

注:转发和重定向最主要区别,转发是一次http request请求,发生在服务端,而重定向是两次请求,由浏览器触发第二次。

@Controller
public class ViewController {

    @RequestMapping("/testThymeleafView")
    public String testThymeleafView() {
        return "success";
    }

    @RequestMapping("/testForward")
    public String testForward() {
        return "forward:/testThymeleafView";
    }

    @RequestMapping("/testRedirect")
    public String testRedirect() {
        return "redirect:/testThymeleafView";
    }
}

三、视图控制器

有些时候对于一个请求(如首页访问),并不需要通过代码做一些处理,这种情况下我们可以直接使用置视图控制器,进行简单配置,就可实现功能。

    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    <mvc:annotation-driven/>

其中path表示访问路径,view-name表示视图名称,即html页面

annotation-driven是注解驱动,此配置项必须存在,否则代码中基于注解的访问方式都会失效

四、SpringMvc支持PUT\DELETE方式

        由于form表单默认只支持GET\POST两种方式,SpringMvc提供了一个过滤器来间接实现PUT\DELETE。

4.1、配置过滤器

    <!-- 支持PUT\DELETE 过滤器 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

4.2、设置form表单

<form th:action="@{/user}" method="post">
    <input type="hidden" name="omethod" value="put">
    用户名:<input type="text" name="username"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit" value="修改用户put">
</form>

4.3、请求处理

    @RequestMapping(value = "/user", method = RequestMethod.PUT)
    public String updateUser(String username, String password) {
        System.out.println("update user:"+username+",password:"+password);
        return "success";
    }

五、HttpMessageConverter 报文转换器

        用于将http request转成java对象或者将java对象转成http response。springmvc提供两个注解和两个类

@RequestBody 将Request Body转换成String,用于标注在形参
@ResponseBody 将java bean转成http response返回给浏览器,通常是方法的返回值,用于标注在方法上(也可以用于类上)
RequestEntity 用于获取http报文,包括请求头和请求体。用于声明控制器形参类型
ResponseEntity 作为控制器方法的返回值,典型使用场景是文件上传与下载

5.1、导入依赖

springmvc默认使用jackson作为json转化

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>

<!-- 如果使用fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.70</version>
</dependency>

5.2、开启注解驱动

<mvc:annotation-driven/>

如果使用fastjson作为转换器,则需要这样配置 

<mvc:annotation-driven>
     <mvc:message-converters>
         <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/>
     </mvc:message-converters>
</mvc:annotation-driven>

5.3、添加@ResponseBody注解

        将java bean做为返回值,传给浏览器

    @RequestMapping(value = "/testResponseUser", method=RequestMethod.GET)
    @ResponseBody
    public User testUser() {
        System.out.println("testUser。。。。");
        return new User(1001, "ZHANGSAN", "1234", "男");
    }

六、文件上传与下载

6.1、下载

        下载功能比较简单,代码如下:

    /* 下载 */
    @RequestMapping("/testDown")
    public ResponseEntity<byte[]> testDown(HttpSession session) throws IOException {
        ServletContext servletContext = session.getServletContext();
        String path = servletContext.getRealPath("/statics/b.png");
        InputStream inputStream = new FileInputStream(path);
        byte[] data = new byte[inputStream.available()];
        inputStream.read(data);

        MultiValueMap<String, String> headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment;filename=aa.png");
        HttpStatus status = HttpStatus.OK;
        ResponseEntity responseEntity = new ResponseEntity<byte[]>(data, headers, status);
        inputStream.close();
        return responseEntity;
    }

6.2、上传

        上传需要导入依赖并且配置文件上传解析器,具体如下:

6.2.1、依赖

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>

6.2.2、文件上传解析器

一定要指定id,否则springmvc不能获取到这个bean

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="utf-8"></property>
    <property name="maxUploadSize" value="10485760000"></property>
    <property name="maxInMemorySize" value="40960"></property>
</bean>

6.2.3、代码

<form action="/testUp" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username" value="1234">
    文件:<input type="file" name="upFile"><br/>
    <input type="submit" name="up" value="up">
</form>
    /**
     * 文件上传
     * 1. commons-fileupload依赖
     * 2. 配置文件上传解析器
     * 3. 形参名字与表单中组件名称保持一致
     */
    @RequestMapping(value = "/testUp", method = RequestMethod.POST)
    public String testUp(MultipartFile upFile, HttpSession session) throws IOException {
        String filename = upFile.getOriginalFilename();
        String updir = session.getServletContext().getRealPath("updir"); //获取服务器路径
        File dir = new File(updir);
        if (!dir.exists()) {//不存在目录则创建
            dir.mkdir();
        }
        File saveFile = new File(updir+File.separator+filename);
        upFile.transferTo(saveFile);
        return "success";
    }

七、拦截器

        拦截器也是可以拦截各种请求(与过滤器功能类似),拦截器(接口)提供了三个方法,三个方法执行时机如下图所示:

多个拦截器执行顺序:

1)所有preHandle方法都返回true

preHandle方法,按照注册顺序执行。postHandle、afterCompletion方法,按照注册顺序反向执行

2)preHandle方法返回false

postHandle方法不会被执行,但是afterCompletion方法会执行

具体可以参考HandlerExecutionChain类中方法:applyPreHandle、applyPostHandle、triggerAfterCompletion

<!-- 配置拦截器 -->
<mvc:interceptors>
    <!-- 拦截所有请求
    <bean class="com.atguigu.interceptors.MyInterceptor"></bean>
    -->
    <mvc:interceptor>
        <!-- 拦截首页之外的所有请求 -->
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/"/>
        <bean class="com.atguigu.interceptors.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor---->preHandle");
        return true; //返回true代表放行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor---->postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor---->afterCompletion");
    }
}

 八、异常处理器

        springmvc提供两种方式用于定制化异常处理:一种是配置方式,一种是基于注解方式。

8.1、配置方式

在springmvc配置文件中增加异常处理器

<!-- 异常解析器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <!-- key=异常全路径名称 算数异常  value=视图名字, 此处实际执行errors.html -->
            <prop key="java.lang.ArithmeticException">errors</prop>
        </props>
    </property>
    <!-- 将错误详细信息exceptionAttribute 放到请求域中,请求域key是exinfo -->
    <property name="exceptionAttribute" value="exinfo"/>
</bean>
<!-- errors.html -->

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Errors</h1>
<p th:text="${exinfo}"></p>
</body>
</html>
    @RequestMapping(value = "/testException", method = RequestMethod.GET)
    public String testException() {
        int a = 1;
        int b = 0;
        int c = a / b;
        return "success";
    }

8.2、基于注解方式异常处理

@ControllerAdvice
public class ExceptionController {
    @ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
    public String errors(Model model, Exception ex) {
        model.addAttribute("exinfo", ex);
        return "errors";
    }
}

 九、SpringMvc基于注解方式开发

        spring提供了一种基于注解方式来替换xml配置文件,那么springmvc也是支持的。下面来介绍一些类,来完成之前的基于xml配置的功能

9.1、继承AbstractAnnotationConfigDispatcherServletInitializer并实现抽象方法

这个实现类不需要任何注解进行标注,在启动时自动被加载

package com.atguigu.config;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;

/**
 * SpringMvc web工程初始化类,用于替换web.xml文件
 */
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * 指定spring的配置类
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    /**
     * 指定springmvc的配置类
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    /**
     * 指定DispatchServlet的映射规则,即url-pattern
     * @return
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    //两个过滤器
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceResponseEncoding(true);

        HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{filter, methodFilter};
    }


}

9.2、SpringMvc配置类

        用一个类来代表springmvc.xml配置文件,这个类需要用@Configuration进行标注

package com.atguigu.config;

import com.atguigu.config.com.atguigu.interceptor.MyInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.thymeleaf.spring5.ISpringTemplateEngine;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;

import java.util.List;
import java.util.Properties;

/**
 * 需要实现以下功能
 * 1.包扫描 2.视图解析器 3.静态资源访问default-servlet-handler
 * 4.视图控制器view-controller 5.开启注解驱动annotation-driven
 * 6.异常处理器  7.拦截器 8.文件上传解析器
 *
 * 继承webmvcconfigure
 */
@Configuration
//1.包扫描
@ComponentScan("com.atguigu.controller")
//5.开启注解驱动annotation-driven
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

    //2.视图解析器
    @Bean
    public ITemplateResolver createTemplateResolver() {
        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        resolver.setPrefix("/WEB-INF/templates/");
        resolver.setSuffix(".html");
        resolver.setCharacterEncoding("UTF-8");
        resolver.setTemplateMode("HTML5");
        return resolver;
    }

    @Bean
    public ISpringTemplateEngine createTemplateEngine(ITemplateResolver resolver) {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(resolver);
        return engine;
    }

    @Bean
    public ViewResolver createViewResolver(ISpringTemplateEngine engine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setOrder(1);
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(engine);
        return viewResolver;
    }

    //3.静态资源访问default-servlet-handler 以下两种方式都可以
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
//    @Override
//    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//        registry.addResourceHandler("/statics/**").addResourceLocations("/statics/");
//    }

    // 4.视图控制器view-controller
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }

    //6.异常处理器
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties props = new Properties();
        props.setProperty("java.lang.ArithmeticException", "errors"); //key=异常全类名, value=视图名字
        resolver.setExceptionAttribute("exinfo");
        resolver.setExceptionMappings(props);
        resolvers.add(resolver);
    }

    //7.拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/");
    }

    //8.文件上传解析器
    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver file = new CommonsMultipartResolver();
        file.setDefaultEncoding("UTF-8");
        file.setMaxUploadSize(10485760000L);
        file.setMaxInMemorySize(40960);
        return file;
    }
}

十、SpringMvc常用配置

webapp\WEB-INF\web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 编码过滤器 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- HiddenHttpMethodFilter -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- servlet -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc04.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

springmvc配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 组件扫描 -->
    <context:component-scan base-package="com.atguigu.controller"/>

    <!-- 视图解析器 -->
    <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <property name="suffix" value=".html"/>
                        <property name="characterEncoding" value="UTF-8"/>
                        <property name="templateMode" value="HTML5"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

    <!-- 开启静态资源访问 -->
    <mvc:default-servlet-handler/>

    <!-- 视图控制器 -->
    <mvc:view-controller path="/" view-name="index"/>
    <mvc:view-controller path="/file" view-name="file"/>

    <!-- 开启注解驱动 -->
    <mvc:annotation-driven>
        <mvc:message-converters> <!-- 处理响应中文乱码问题 -->
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="defaultCharset" value="UTF-8"/>
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html</value>
                        <value>application/json</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>


    <!-- 文件上传解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"></property>
        <property name="maxUploadSize" value="10485760000"></property>
        <property name="maxInMemorySize" value="40960"></property>
    </bean>

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <!-- 拦截所有请求
        <bean class="com.atguigu.interceptors.MyInterceptor"></bean>
        -->
        <mvc:interceptor>
            <!-- 拦截首页之外的所有请求 -->
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/"/>
            <bean class="com.atguigu.interceptors.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

    <!-- 异常解析器 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <!-- key=异常全路径名称  value=视图名字, 此处实际执行errors.html -->
                <prop key="java.lang.ArithmeticException">errors</prop>
            </props>
        </property>
        <!-- 将错误详细信息exceptionAttribute 放到请求域中,请求域key是exinfo -->
        <property name="exceptionAttribute" value="exinfo"/>
    </bean>

</beans>

以上是最近学习springmvc总结,作为一个备份吧。

猜你喜欢

转载自blog.csdn.net/xxb249/article/details/120682895