springMVC笔记

目录

配置springMVC

@RequestMapping注解

SpringMVC支持ant风格的路径

SpringMVC支持路径中的占位符 

SpringMVC获取请求参数

通过控制器方法的形参获取请求参数

域对象共享数据

向request域对象共享数据

向session域共享数据

向application域共享数据

SpringMVC的视图

RESTful 

发送get和post请求:

 发送put和delete请求的方式

 RESTful 实例

 SpringMVC处理ajax请求

@RequestBody

@ResponseBody

@RestController注解

文件上传和下载

拦截器

异常处理器配置(基于注解):

注解配置SpringMVC

SpringMvc完整执行流程


配置springMVC

1.创建maven工程

  1. 添加web模块
  2. 打包方式:war
  3. 引入依赖<dependencies>

配置pom.xml

    <packaging>war</packaging>
    <dependencies>
        <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- 日志 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- ServletAPI -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- Spring5和Thymeleaf整合包 -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.12.RELEASE</version>
        </dependency>
        <!--文件上传组件-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
    </dependencies>

2.配置web.xml的两个过滤器一个控制器

<!--配置编码过滤器-->
<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>
<!--配置处理请求方式put和delete的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>
<!--配置springMVC的前端控制器DispatcherServlet-->
<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:springMVC.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>

3.resources文件夹下创建springMVC.xml文件

4.创建springMVC的配置文件

    <!--开启扫描-->
    <context:component-scan base-package="com.gr"></context:component-scan> 
    <!-- 配置Thymeleaf视图解析器 -->
    <bean id="viewResolver" 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="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    <!--
        配置默认的servlet处理静态资源
        当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是/
        tomcat的wbe.xml配置的DefaultServlet的url-pattern是/
        此时,浏览器发送的请求会优先被DispatcherServlet进行处理,但是DispatcherServlet无法处理静态资源
        若配置了<mvc:default-servlet-handler/>,此时浏览器发送的所有请求都会被DispatcherServlet处理
        若配置了<mvc:default-servlet-handler/>和<mvc:annotation-driven/>
        浏览器发送的请求会先被DispatcherServlet处理,无法处理再交给DefaultServlet处理
    -->
    <mvc:default-servlet-handler/>
    <!--开启mvc的注解驱动-->
    <mvc:annotation-driven/>
    <!--配置视图控制器-->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    <!--配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
    

@RequestMapping注解

标记的位置:

@RequestMapping标识一个类:设置映射请求的请求路径的初始信息,相当于添加一层路径

@RequestMapping标识一个方法:设置映射请求请求路径的具体信息

例:

@Controller
@RequestMapping("/test")
public class RequestMappingController {
    //此时请求映射所映射的请求的请求路径为:/test/testRequestMapping
    @RequestMapping("/testRequestMapping")
    public String testRequestMapping(){}
}

属性:

value:通过请求的请求地址匹配请求映射(数组多选一)

method:通过请求的请求方式(get或post)匹配请求映射(数组多选一)

        处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解:

                处理get请求的映射-->@GetMapping

                处理post请求的映射-->@PostMapping

                处理put请求的映射-->@PutMapping

                处理delete请求的映射-->@DeleteMapping

params:通过请求的请求参数匹配请求映射,若不满足报400(多满足)

headers:通过请求的请求头信息必须满足headers属性的设置,若不满足报404(多满足)

常用设置: 

@RequestMapping(
    value = {"/testRequestMapping", "/test"},
    method = {RequestMethod.GET, RequestMethod.POST},
    //params = {"username","password!=123456"}
)

SpringMVC支持ant风格的路径

?:表示任意的单个字符

*:表示任意的0个或多个字符

**:表示任意层数的任意目录

注意:在使用**时,只能使用/**/xxx的方式

例如:

//<a th:href="@{/aaa/test/ant}"></a> 
@RequestMapping("a*/**/a?t")
 public String testAnt(){
     return "success";
 }

SpringMVC支持路径中的占位符 

//<a th:href="@{/testRest/1/admin}"></a>
@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id, @PathVariable("username")String username){
    System.out.println("id:"+id+",username:"+username);
    return "success";
}
//最终输出的内容为-->id:1,username:admin

SpringMVC获取请求参数

通过控制器方法的形参获取请求参数

在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在 DispatcherServlet中就会将请求参数赋值给相应的形参

//<a th:href="@{/testParam(username='admin',password='123456')}"></a>
@RequestMapping("/testParam")
public String testParam(String username, String password){
    System.out.println("username:"+username+",password:"+password);
    return "success";
}

若前端请求参数与控制器方法名不同,则需要使用以下注解: 

@RequestParam  是将请求参数和控制器方法的形参绑定

@RequestHeader  是将请求头信息和控制器方法的形参绑定

@CookieValue       是将cookie数据和控制器方法的形参绑定

以上三个注解都具有以下三个属性:

value:设置和形参绑定的请求参数的名字

required设置是否必须传输value所对应的请求参数(参数是否可以为null),默认值为true 若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置 defaultValue 属性,则页面报错400:Required String parameter 'xxx' is not present;若设置为 false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为 null

defaultValue设置默认值;不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值 为""时,则使用默认值为形参赋值

//<a th:href="@{/testParam(userName='admin',password='123456')}"></a>
@RequestMapping("/testParam")
public String testParam(
            @RequestParam(value = "userName",required = false,defaultValue = "hehe")
            String username, String password
            @RequestHeader("referer") String referer,
            @CookieValue("JSESSIONID") String jsessionId){
    System.out.println("username:"+username+",password:"+password);
    return "success";
}

通过POJO获取请求参数

创建User类(属性名要与请求参数名字一致)

html文件内:

<form th:action="@{/testpojo}" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    性别:<input type="radio" name="sex" value="男">男
         <input type="radio" name="sex" value="女">女<br>
    年龄:<input type="text" name="age"><br>
    邮箱:<input type="text" name="email"><br>
    <input type="submit" value="使用实体类接受请求参数">
</form>
@RequestMapping("/testpojo")
public String testPOJO(User user){
    System.out.println(user);
    return "success";
}

域对象共享数据

向request域对象共享数据

ModelAndView

Model:向请求域中共享数据

view:设置逻辑视图实现页面跳转

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
     ModelAndView mav = new ModelAndView();
     //处理模型数据,即向请求域request共享数据
     mav.addObject("testRequestScope","hello,ModelAndView");
     //设置视图名称
     mav.setViewName("success");
     return mav;
 }

Model

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

map

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

ModelMap

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

向session域共享数据

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

向application域共享数据

@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
    ServletContext application = session.getServletContext();
    application.setAttribute("testApplicationScope", "hello,application");
    return "success";
}

SpringMVC的视图

无前缀:ThymeleafView

以"forward:"为前缀: InternalResourceView  转发视图

以"redirect:"为前缀: RedirectView  重定向视图

例如:

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

视图控制器view-controller

<!--path:设置处理的请求地址   view-name:设置请求地址所对应的视图名称-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>

当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需 要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:

<mvc:annotation-driven />

RESTful 

根据请求方式不同分为各种功能:

        GET 用来获取资源

        POST 用来新建资源

        PUT 用来更新资源

        DELETE 用来删除资源

发送get和post请求:

查询所有用户信息:

//<a th:href="@{/user}">查询所有的用户信息</a><br>
@GetMapping("/user")
public String getAllUser(){
    System.out.println("查询所有的用户信息  -->/user-->get");
    return "success";
}

跟据id查询用户信息:

//<a th:href="@{/user/1}">查询id为1的用户信息</a><br>
@GetMapping("/user/{id}")
public String getUserById(@PathVariable("id") Integer id){
    System.out.println("根据id查询用户信息  -->/user/"+id+"-->get");
    return "success";
}

添加用户信息:

/*
<form th:action="@{/user}" method="post">
    <input type="submit" value="添加用户信息">
</form>
*/
@PostMapping("/user")
public String insertUser(){
    System.out.println("添加用户信息-->/user-->post");
    return "success";
}

 发送put和delete请求的方式

在web.xml中配置HiddenHttpMethodFilter过滤器:

<!--配置处理请求方式put和delete的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>

当前请求的请求方式必须为post

当前请求必须传输请求参数_method 

<form th:action="@{/user}" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="submit" value="修改用户信息">
</form>

修改用户信息

@PutMapping("/user")
public String updateUser(){
    System.out.println("修改用户信息-->/user-->put");
    return "success";
}

 删除用户信息

/*
<form th:action="@{/user/1}" method="post">
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="删除用户信息">
</form>
*/
@DeleteMapping("/user/{id}")
public String deleteUser(@PathVariable("id") Integer id){
    System.out.println("删除用户信息-->/user/"+id+"-->delete");
    return "success";
}

 RESTful 实例

查询: 显示所有员工

    <table>
        <tr>
            <th colspan="5">employee_list</th>
        </tr>
        <tr>
            <th>id</th>
            <th>lastName</th>
            <th>email</th>
            <th>gender</th>
            <th>options(<a th:href="@{/to/add}">add</a> )</th>
        </tr>
        <tr th:each="employee : ${allEmployee}">
            <td th:text="${employee.id}"></td>
            <td th:text="${employee.email}"></td>
            <td th:text="${employee.lastName}"></td>
            <td th:text="${employee.gender}"></td>
            <td>
                <a @click="deleteEmployee()" th:href="@{|/employee/${employee.id}|}">delete</a>
                <a th:href="@{|/employee/${employee.id}|}">update</a>
            </td>
        </tr>
    </table>
    @GetMapping("/employee")
    public String getAllEmployee(Model model){
        //获取所有员工信息
        Collection<Employee> allEmployee = employeeDao.getAll();
        //将所有的员工信息在请求域中共享
        model.addAttribute("allEmployee",allEmployee);
        return "employee_list";
    }

添加: 添加员工界面

<body>
<form th:action="@{/employee}" method="post">
    <table>
        <tr>
            <th colspan="2">add employee</th>
        </tr>
        <tr>
            <td>lastName</td>
            <td>
                <input type="text" name="lastName">
            </td>
        </tr>
        <tr>
            <td>email</td>
            <td>
                <input type="text" name="email">
            </td>
        </tr>
        <tr>
            <td>gender</td>
            <td>
                <input type="radio" name="gender" value="1">male
                <input type="radio" name="gender" value="0">female
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="add">
            </td>
        </tr>
    </table>
</form>
</body>
    @PostMapping("/employee")
    public String insertEmployee(Employee employee){
        //保存员工信息
        employeeDao.save(employee);
        //重定向到列表功能:/employee
        return "redirect:/employee";
    }

 修改: 获取要修改对象信息,放入请求域中

    @GetMapping("/employee/{id}")
    public String getEmployeeById(@PathVariable("id") Integer id,Model model){
        Employee employee = employeeDao.get(id);
        model.addAttribute("employee",employee);
        return "employee_update";
    }

修改界面:

<body>
<form th:action="@{/employee}" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="hidden" name="id" th:value="${employee.id}">
    <table>
        <tr>
            <th colspan="2">update employee</th>
        </tr>
        <tr>
            <td>lastName</td>
            <td>
                <input type="text" name="lastName" th:value="${employee.lastName}">
            </td>
        </tr>
        <tr>
            <td>email</td>
            <td>
                <input type="text" name="email" th:value="${employee.email}">
            </td>
        </tr>
        <tr>
            <td>gender</td>
            <td>
                <input type="radio" name="gender" value="1" th:field="${employee.gender}">male
                <input type="radio" name="gender" value="0" th:field="${employee.gender}">female
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="update">
            </td>
        </tr>
    </table>
</form>
</body>
    @PutMapping("/employee")
    public String updateEmployee(Employee employee){
        employeeDao.save(employee);
        return "redirect:/employee";
    }

删除: 使用vue将超链接get请求与form表单的delete请求绑定

<body>
<div id="app">
    <table>
        <tr>
            <th colspan="5">employee_list</th>
        </tr>
        <tr>
            <th>id</th>
            <th>lastName</th>
            <th>email</th>
            <th>gender</th>
            <th>options(<a th:href="@{/to/add}">add</a> )</th>
        </tr>
        <tr th:each="employee : ${allEmployee}">
            <td th:text="${employee.id}"></td>
            <td th:text="${employee.email}"></td>
            <td th:text="${employee.lastName}"></td>
            <td th:text="${employee.gender}"></td>
            <td>
                <a @click="deleteEmployee()" th:href="@{|/employee/${employee.id}|}">delete</a>
                <a th:href="@{|/employee/${employee.id}|}">update</a>
            </td>
        </tr>
    </table>
    <form method="post">
        <input type="hidden" name="_method" value="delete">
    </form>
</div>

<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript">
    var vue = new Vue({
        el: "#app",
        methods: {
            deleteEmployee() {
                //获取form表单
                var form = document.getElementsByTagName("form")[0];
                //将超链接的href属性值赋值给form表单的action属性
                //event.target表示当前触发事件的标签
                form.action = event.target.href;
                //表单提交
                form.submit();
                //阻止超链接的默认行为
                event.preventDefault();
            }
        }
    });
</script>
</body>
    @DeleteMapping("/employee/{id}")
    public String deleteEmployee(@PathVariable("id") Integer id){
        employeeDao.delete(id);
        return "redirect:/employee";
    }

 SpringMVC处理ajax请求

@RequestBody

@RequestBody可以获取请求体信息,使用@RequestBody注解标识控制器方法的形参,当前请求的请 求体就会为当前注解所标识的形参赋值

<!--此时必须使用post请求方式,因为get请求没有请求体-->
<form th:action="@{/test/RequestBody}" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit">
</form>
@RequestMapping("/test/RequestBody")
public String testRequestBody(@RequestBody String requestBody){
    System.out.println("requestBody:"+requestBody);
    return "success";
}
//输出结果:requestBody:username=admin&password=123456

@RequestBody获取json格式的请求参数 

 在使用了axios发送ajax请求之后,浏览器发送到服务器的请求参数有两种格式:

1、name=value&name=value...,此时的请求参数可以通过request.getParameter()获取,对应 SpringMVC中,可以直接通过控制器方法的形参获取此类请求参数

2、{key:value,key:value,...},此时无法通过request.getParameter()获取,之前我们使用操作 json的相关jar包gson或jackson处理此类请求参数,可以将其转换为指定的实体类对象或map集合。在SpringMVC中,直接使用@RequestBody注解标识控制器方法的形参即可将此类请求参数转换为java对象

使用@RequestBody获取json格式的请求参数的条件

1、导入jackson的依赖

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

2、SpringMVC的配置文件中设置开启mvc的注解驱动

<!--开启mvc的注解驱动-->
<mvc:annotation-driven />

3、在控制器方法的形参位置,设置json格式的请求参数要转换成的java类型(实体类或map)的参 数,并使用@RequestBody注解标识

<input type="button" value="测试@RequestBody获取json格式的请求参数" @click="testRequestBody()"><br>
<script type="text/javascript" th:src="@{/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/js/axios.min.js}"></script>
<script type="text/javascript">
    var vue = new Vue({
        el:"#app",
        methods:{
            testRequestBody(){
                axios.post(
                    "/SpringMVC/test/RequestBody/json",
                    {username:"admin",password:"123456"}
                ).then(response=>{
                    console.log(response.data);
            });
            }
        }
    });
</script>
//将json格式的数据转换为map集合
@RequestMapping("/test/RequestBody/json")
public void testRequestBody(@RequestBody Map<String, Object> map,HttpServletResponse response) throws IOException {
    System.out.println(map);
    //{username=admin, password=123456}
    response.getWriter().print("hello,axios");
}
//将json格式的数据转换为实体类对象
@RequestMapping("/test/RequestBody/json")
public void testRequestBody(@RequestBody User user, HttpServletResponse response) throws IOException {
    System.out.println(user);
    //User{id=null, username='admin', password='123456', age=null,gender='null'}
    response.getWriter().print("hello,axios");
}

@ResponseBody

@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到 浏览器

@RequestMapping("/testResponseBody")
public String testResponseBody(){
    //此时会跳转到逻辑视图success所对应的页面
    return "success";
}
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
    //此时响应浏览器数据success
    return "success";
}

@ResponseBody响应浏览器json数据

服务器处理ajax请求之后,大多数情况都需要向浏览器响应一个java对象,此时必须将java对象转换为 json字符串才可以响应到浏览器,之前我们使用操作json数据的jar包gson或jackson将java对象转换为 json字符串。在SpringMVC中,我们可以直接使用@ResponseBody注解实现此功能

@ResponseBody响应浏览器json数据的条件:

1、导入jackson的依赖

2、SpringMVC的配置文件中设置开启mvc的注解驱动

3、使用@ResponseBody注解标识控制器方法,在方法中,将需要转换为json字符串并响应到浏览器 的java对象作为控制器方法的返回值,此时SpringMVC就可以将此对象直接转换为json字符串并响应到 浏览器

<input type="button" value="测试@ResponseBody响应浏览器json格式的数据"@click="testResponseBody()"><br>
<script type="text/javascript" th:src="@{/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/js/axios.min.js}"></script>
<script type="text/javascript">
    var vue = new Vue({
        el:"#app",
        methods:{
            testResponseBody(){
            axios.post("/SpringMVC/test/ResponseBody/json").then(response=>{
                console.log(response.data);
                });
            }
        }
    });
</script>
//响应浏览器list集合
@RequestMapping("/test/ResponseBody/json")
@ResponseBody
public List<User> testResponseBody(){
    User user1 = new User(1001,"admin1","123456",23,"男");
    User user2 = new User(1002,"admin2","123456",23,"男");
    User user3 = new User(1003,"admin3","123456",23,"男");
    List<User> list = Arrays.asList(user1, user2, user3);
    return list;
}
//响应浏览器map集合
@RequestMapping("/test/ResponseBody/json")
@ResponseBody
public Map<String, Object> testResponseBody(){
    User user1 = new User(1001,"admin1","123456",23,"男");
    User user2 = new User(1002,"admin2","123456",23,"男");
    User user3 = new User(1003,"admin3","123456",23,"男");
    Map<String, Object> map = new HashMap<>();
    map.put("1001", user1);
    map.put("1002", user2);
    map.put("1003", user3);
    return map;
}
//响应浏览器实体类对象
@RequestMapping("/test/ResponseBody/json")
@ResponseBody
public User testResponseBody(){
    return user;
}

@RestController注解

@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了 @Controller注解,并且为其中的每个方法添加了@ResponseBody注解

文件上传和下载

文件下载

@Controller
public class FileUpAndDownController {
    @RequestMapping("/testDown")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath = servletContext.getRealPath("/static/img/1.png");        
        //创建输入流
        InputStream is = new FileInputStream(realPath);
        //创建字节数组
        byte[] bytes = new byte[is.available()];
        //将流读到字节数组中
        is.read(bytes);
        //创建HttpHeaders对象设置响应头信息
        MultiValueMap<String, String> headers = new HttpHeaders();
        //设置要下载方式以及下载文件的名字
        headers.add("Content-Disposition", "attachment;filename=1.png");
        //设置响应状态码
        HttpStatus statusCode = HttpStatus.OK;
        //创建ResponseEntity对象
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
        //关闭输入流
        is.close();
        return responseEntity;
}

文件上传

文件上传要求form表单的请求方式必须为post,并且添加属性enctype="multipart/form-data"

SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息

    <form th:action="@{/test/up}" method="post" enctype="multipart/form-data">
        头像:<input type="file" name="photo"><br>
        <input type="submit" value="上传">
    </form>

上传步骤:

1.添加依赖:

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

2.在SpringMVC的配置文件中添加配置:

<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

3.控制器方法:

@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
        //getOriginalFilename():获取上传文件的文件名
        String fileName = photo.getOriginalFilename();
        //处理文件重名问题
        //获取上传的文件的后缀名
        String hzName = fileName.substring(fileName.lastIndexOf("."));
        //UUID中”-”替换为””,拼接为新的文件名
        fileName = UUID.randomUUID().toString().replaceAll("-","") + hzName;
        //通过ServletContext获取服务器中photo目录的路径
        ServletContext servletContext = session.getServletContext();
        String photoPath = servletContext.getRealPath("photo");
        File file = new File(photoPath);
        //判断photoPath所对应的路径是否存在
        if (!file.exists()) {
            //若不存在则创建目录
            file.mkdir();
        }
        String finalPath = photoPath + File.separator + fileName;
        //实现上传功能
        photo.transferTo(new File(finalPath));
        return "success";
}

拦截器

以下两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截 

<mvc:interceptors>
   <bean class="com.gr.controller.FirstInterceptor"></bean>      
</mvc:interceptors>

引用一个类作为拦截器,可配置也在类名上加@Component注解.以配置为例:

<bean id="firstInterceptor" class="com.gr.controller.FirstInterceptor"></bean>
<mvc:interceptors>    
    <ref bean="firstInterceptor"></ref>   
</mvc:interceptors>

以下配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过

mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求

<mvc:interceptors>
    <mvc:interceptor>
        <!--配置需要拦截的请求的请求路径,/**表示所有请求-->
        <mvc:mapping path="/**"/>
        <!--配置需要排除拦截的请求的请求路径-->
        <mvc:exclude-mapping path="/"/>
        <!--配置拦截器-->
        <ref bean="firstInterceptor"></ref>
    </mvc:interceptor>
</mvc:interceptors>

SpringMVC中的拦截器需要实现HandlerInterceptor,实现拦截器的三个抽象方法:

preHandle:控制器方法执行之前执行,其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法

postHandle:控制器方法执行之后执行

afterComplation:处理完视图和模型数据,渲染视图完毕之后执行

@Component
public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor-->preHandle");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor-->postHandle");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor-->afterCompletion");
    }
}

多个拦截器的执行顺序:

①若每个拦截器的preHandle()都返回true 此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关: preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行

②若某个拦截器的preHandle()返回了false preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false 的拦截器之前的拦截器的afterCompletion()会执行

异常处理器配置(基于注解):

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

前端显示异常信息:

<p th:text="${ex}"></p>

注解配置SpringMVC

1.配置资源

 2.注解配置SpringMVC

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    //设置一个配置类,代替Spring的配置文件
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }
    //设置一个配置类,代替SpringMVC的配置文件
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }
    //设置SpringMVC的前端控制器DispatcherServlet的url-pattern
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    @Override
    //设置当前的过滤器
    protected Filter[] getServletFilters() {
        //创建编码过滤器
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceResponseEncoding(true);
        //创建处理请求方式的过滤器
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{characterEncodingFilter,hiddenHttpMethodFilter};
    }
}

3.创建SpringConfig配置类,代替spring的配置文件

@Configuration
public class SpringConfig {
    //ssm整合之后,spring的配置信息写在此类中
}

4.创建WebConfig配置类,代替SpringMVC的配置文件

@Configuration
//扫描组件
@ComponentScan("com.gr.controller")
//开启mvc的注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    //默认的Servlet处理静态资源
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
    //配置视图控制器
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }
    //文件上传解析器
    @Bean
    //@Bean注解可以将表示的方法的返回值作为Bean进行管理,Bean的id为方法的方法名
    public CommonsMultipartResolver multipartResolver() {
        return new CommonsMultipartResolver();
    }
    //拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        FistInterceptor fistInterceptor = new FistInterceptor();
        registry.addInterceptor(fistInterceptor).addPathPatterns("/**").excludePathPatterns("/");
    }
    //配置异常解析器
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
        Properties prop = new Properties();
        prop.setProperty("java.lang.ArithmeticException", "error");
        exceptionResolver.setExceptionMappings(prop);
        exceptionResolver.setExceptionAttribute("ex");
        resolvers.add(exceptionResolver);
    }
    //配置生成模板解析器
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }
    //生成模板引擎并为模板引擎注入模板解析器
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }
    //生成视图解析器并未解析器注入模板引擎
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }
}

SpringMvc完整执行流程

浏览器发送请求,被DispatcherServlet处理.

DispatcherServlet处理请求时要找到请求对应的请求映射,这时就有两种情况:存在或者不存在

不存在的话再去找有没有配置默认的servlet,如果也没有则直接报404错误

有配置了的话则直接交给默认的servlet继续来处理.

默认的servlet也找不到的话页面也是报404错误

找到了这个请求映射的话就通过HandlerMapping去匹配当前的控制器方法

匹配到之后再由HandlerAdapter调用执行控制器方法

在执行控制器方法之前会按照配置的拦截器顺序去执行拦截器的preHandler方法

接着再调用控制器方法

控制器方法执行之后调用拦截器的postHandle方法

postHandle方法执行之后就要来处理ModelAndView,来渲染视图

渲染视图之后执行拦截器的afterCompletion方法

最终将结果相应到浏览器

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值