目录

  • 三层架构
  • MVC模型
  • SpringMVC概述
  • springmvc是什么
  • springmvc和structs2比较
  • springmvc 环境搭建
  • spring的配置文件头部
  • 入门程序编写
  • springmvc工作流程(原理)
  • 解决post请求中文乱码问题(使用过滤器filter)
  • 请求参数绑定
  • 自定义类型转换器
  • 获取原生servlet的API
  • 常见注解
  • @RequestMapping
  • @RequestParam
  • @RequestBody
  • @PathVariable
  • @RequestHeader(用的较少)
  • @CookieValue
  • @ModelAttribute
  • @SessionAttributes
  • restful编程风格
  • 响应请求的四种方式
  • 响应之后返回值是string类型
  • 响应之后返回值是void类型
  • 响应之后返回值是ModelAndVies类型
  • 使用forward和redirect关键字进行页面跳转
  • 发送ajax请求并响应(数据传输以json格式进行传输)
  • 文件上传
  • 传统方式
  • springmvc文件上传
  • 跨服务器实现文件上传
  • springmvc的异常处理
  • 异常处理思路
  • springmvc异常处理示例小代码
  • springmvc拦截器
  • springmvc拦截器入门小程序


三层架构

我们的开发一般有两种形式:C/S架构,B/S架构,在JavaEE开发中,几乎都是基于B/S架构的开发。那么在B/S架构中,服务器端,系统标准的三层架构包括:表现层,业务层,持久层。

javaFX Alert按钮样式_xml

MVC模型

MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

  • Model(模型)
    代表一个存取数据的java对象,也就是javaBean。
  • Vide(视图)
    通常是我们的jsp或html,用于展示数据,一般依据数据模型创建的
  • Controller(控制器)
  • 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
  • javaFX Alert按钮样式_xml_02

SpringMVC概述

springmvc是什么

srpingmvc是一种基于java的实现mvc设计模型的请求驱动类型的轻量级web框架,属于spring framework的后续产品。支持resrful编程风格的请求。

springmvc和structs2比较

共同点:
1)都是表现层框架,都是基于mvc模型编写的
2)底层都是原始servletAPI
3)处理请求的机制都是一个核心控制器
区别:
1)spring mvc的入口是servllet,而structs2是filter
2)spring mvc(对象单例)是基于方法设计的,而structs(多例) 是基于类,structs是每次执行都会创建一个动作类,因此spring mvc 会比较快
3)spring mvc 使用更简洁,支持JSR303,处理ajax更方便
(JSR303 是一套javabean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们javabean的属性上,就可以在需要校验的时候进行校验了)
4)structs的OGNL表达式使页面的开发效率优于spring mvc,但是执行效率并没有比JSTL提升,尤其是strucrs2的表单标签,远没有html执行效率高

springmvc 环境搭建

1)创建maven工程,选择

javaFX Alert按钮样式_mvc_03


2):在创建Maven工程时加上 archetypeCatalog=internal参数

javaFX Alert按钮样式_spring_04


3)导入依赖

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>


    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>


    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>


    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>



    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>



    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

4)补全目录结构

javaFX Alert按钮样式_spring_05


5)在web.xml中配置拦截

<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

spring的配置文件头部

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.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">

    <mvc:annotation-driven/>

</beans>

入门程序编写

实现点击页面链接,跳转页面

  • web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  
  <servlet>
    <!--配置前端可控制器-->
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--添加属性,加载springmvc.xml-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--使springmvc.xml在程序一运行就加载-->
    <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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.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">

    <!--开启spring的注解扫描-->
    <context:component-scan base-package="com.hwh"></context:component-scan>
    <!--开启springmvc的注解扫描-->
    <mvc:annotation-driven/>

    <!--配置视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>
  • HelloController.java
package com.hwh.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.xml.ws.RequestWrapper;

/**
 * @Description TODO
 * @Author hwh
 * @Date 2020/1/5 16:14
 **/
@Controller
public class HelloController {

    @RequestMapping(path = "/hello")
    public String first(){
        System.out.println("success");

        return "success";
    }
}
  • index.jsp
<%--
  Created by IntelliJ IDEA.
  User: AIR
  Date: 2020/1/5
  Time: 16:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>入门程序11</h1>
    <a href="hello">点击入门程序</a>
</body>
</html>
  • success.jsp
<%--
  Created by IntelliJ IDEA.
  User: AIR
  Date: 2020/1/5
  Time: 16:13
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>成功</h1>
</body>
</html>

springmvc工作流程(原理)

springmvc是基于组件方式执行流程,所谓组件就是各个器,如处理器映射器等

  • 根据代码进行简单分析

javaFX Alert按钮样式_xml_06

  • 详细介绍

javaFX Alert按钮样式_javaFX Alert按钮样式_07


1)客户端发送请求到前端控制器

2)前端控制器让处理器映射器(HandlerMapping)去查找handler(也就是controller类中的方法),并返回一个执行链

3)通过处理器适配器,找到响应的Handler(处理器),执行handler方法,并返回一个modelandview

4)通过视图解析器去解析modelandview并返回一个view

5)渲染到视图,展示给客户

  • 各个组件
    1)DispatherServlet(前端控制器):
    整个流程的控制中心,它的存在可以降低各个组件间的耦合性
    2)HandlerMapping(处理器映射器)
    根据用户请求,找到响应的处理器(hander)
    3)Handler(处理器)
    开发中要编写的具体业务控制器
    4)HandlAdapter(处理器适配器)
    找到响应的适配器
    5)View Resolver (视图解析器)
    将处理结果生成view
    6)View(视图)
    渲染页面

注意

<mvc:annotation-driven/>  自动加载处理器映射器和处理器适配器

解决post请求中文乱码问题(使用过滤器filter)

<!--解决中文乱码问题-->
  <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>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

请求参数绑定

  • 传递对象以及对象中包含对象的情况
    jsp发送请求:
<form action="test" method="post">
        姓名:
        <input type="text" name="userName"><br>
        密码:
        <input type="text" name="password"><br>
        用户姓名:
        <input type="text" name="user.uname"><br>
        性别:
        <input type="text" name="user.sex"><br>
        <input type="submit" value="提交">

    </form>

controller层接受请求:

@RequestMapping(path = "/test")
    private String testParam(Account account){
        System.out.println(account);
        System.out.println(account.getUser());
        return "success";
    }
  • 参数绑定集合类型

account类

private Integer id;
    private String userName;
    private String password;

    private List<User> userList;
    private Map<String,User> userMap;

jsp

<form action="test" method="post">
        姓名:
        <input type="text" name="userName"><br>
        密码:
        <input type="text" name="password"><br>


        用户姓名:
        <input type="text" name="userList[0].uname"><br>
        性别:
        <input type="text" name="userList[0].sex"><br>

        用户姓名:
        <input type="text" name="userMap['one'].uname"><br>
        性别:
        <input type="text" name="userMap['one'].sex"><br>
        <input type="submit" value="提交">

    </form>

controller类

@RequestMapping(path = "/test")
    private String testParam(Account account){
        System.out.println(account);
        return "success";
    }

自定义类型转换器

步骤:
1、编写转换类,继承于converter接口、

package com.hwh.utils;


import javafx.scene.input.DataFormat;
import org.springframework.core.convert.converter.Converter;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Description TODO
 * @Author hwh
 * @Date 2020/1/7 11:14
 **/
public class StringConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        if(s==null){
            throw new RuntimeException("没有参数传入");
        }
        try {
            DateFormat df = new SimpleDateFormat("yy-MM-dd");
            return df.parse(s);
        } catch (ParseException e) {
            throw new RuntimeException("数据类型转换出现错误");
        }
    }
}

2、在xml中创建ConversionServiceFactoryBean的bean对象,并将自定义转换器注入

<!--注册自定义类型转换器-->
    <bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
       <property name="converters">
           <set>
               <bean class="com.hwh.utils.StringConverter"></bean>
           </set>
       </property>
    </bean>

3、让方法生效

<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>

获取原生servlet的API

/**
     * 获取原生servlet的API
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(path = "/selvet")
    private String getServletAPI(HttpServletRequest request, HttpServletResponse response){
        System.out.println(request);
        HttpSession session = request.getSession();
        System.out.println(session);
        System.out.println(response);
        return "success";
    }

常见注解

@RequestMapping

  • 作用
    建立请求url和处理请求方法之间的对应关系
  • 位置
    可以添加在类上或者方法上,添加在类上相当于建立一级目录,而添加在方法上相当于建立二级目录,有利于分模块开发
  • 属性
    1)path:配置映射路径
    2)value:与path作用同
    3)method:当前的方法可以接受什么样的请求方式,get或post
method = {RequestMethod.GET}

4)params:指定限制请求参数的条件

params = {"username"} 表示所发送的请求必须传username属性,否则方法不执行

5)headers:发送的请求必须包含请求头

@RequestParam

当插入参数名称与接收时名称不一致的情况下使用
示例:

<a href="requestParam?username=hh">点击入门程序</a>
@RequestMapping(path = "/requestParam")
    private String requestParam(@RequestParam("username") String name){
        System.out.println(name);
        return "success";
    }

@RequestBody

作用:用于获得请求体内容,直接使用得到的是key=value&key=value…结构的数据。
get方法不适用
用法:

@RequestMapping(path = "/RequestBody")
    private String testRequestBody(@RequestBody User user){
        System.out.println(user);
        return "success";
    }

@PathVariable

作用:用于绑定url中的占位符,获取占位符中内容,在使用restful的编程风格的时候通常会用到。
代码示例:

<a href="PathVariable/10">点击入门程序</a>
@RequestMapping(path = "/PathVariable/{uid}")
    private String testPathVariable(@PathVariable(value = "uid") Integer id){
        System.out.println(id);
        return "success";
    }

@RequestHeader(用的较少)

作用:用于获取请求消息头,可以用于反爬虫
属性
value:提供消息头名称(如Accpet)
required:是否必须有此消息头
代码示例

@RequestMapping(path = "/PathVariable")
    private String testPathVariable(@RequestHeader(value = "Accept") String header){
        System.out.println(header);
        return "success";
    }

@CookieValue

作用:获取指定cookie名称的值
属性
value 指定cookie的名称
required 是否不许有此cookie
示例代码

@RequestMapping(path = "/CookieValue")
    private String testCookieValue(@CookieValue(value = "JSESSIONID") String cookie){
        System.out.println(cookie);
        return "success";
    }

@ModelAttribute

作用
该注解是springmvc4.3版本以后新加入的,他可以用于修饰方法和参数
出现在方法上,表示当前方法会在控制器方法执行之前先执行。它可以修饰没有返回值的方法,也可以修饰具有返回值的方法。
出现在参数上,获取指定的数据给参数赋值
属性
value:用于获取数据的key,key可以是POJO的属性名称,也可以是map结构的key
应用场景
当表单提交不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据
代码示例
jsp代码:

<%--
  Created by IntelliJ IDEA.
  User: AIR
  Date: 2020/1/5
  Time: 16:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>入门程序11</h1>
    <form action="user" method="post">
        用户名:
        <input type="text" name="uname"><br>
        性别:
        <input type="text" name="sex"><br>
        <input type="submit" value="提交">

    </form>
</body>
</html>
  • 当用在方法上时(也就是方法有返回值的情况)

controller类方法

@RequestMapping(path = "/user")
    public String getUser(User user){
        System.out.println("------getUser执行了-------");
        System.out.println(user);

        return "success";
    }

    @ModelAttribute
    public User beforeUser(String username){
        System.out.println("------beforeUser执行了-------");
        //模拟通过username从数据库中读取user
        User user = new User();
        user.setUname(username);
        user.setSex("女");
        user.setBirthday(new Date());

        return user;
    }
  • 当用在参数上时(也就是方法没有返回值的情况)

controller类方法

@RequestMapping(path = "/user")
    public String getUser(@ModelAttribute(value = "one") User user){
        System.out.println("------getUser1执行了-------");
        System.out.println(user);

        return "success";
    }

    @ModelAttribute
    public void beforeUser(String username, Map<String,User> map){
        System.out.println("------beforeUser1执行了-------");
        //模拟通过username从数据库中读取user
        User user = new User();
        user.setUname(username);
        user.setSex("女");
        user.setBirthday(new Date());
        map.put("one",user);

//        return user;
    }

运行结果:

javaFX Alert按钮样式_javaFX Alert按钮样式_08

@SessionAttributes

作用
用于多次执行控制器方法见的参数共享
属性
value:用于指定存入的属性名称
type:用于指定存入的数据类型
代码示例
jsp中的代码:

<%--
  Created by IntelliJ IDEA.
  User: AIR
  Date: 2020/1/5 
  Time: 16:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java"  %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>入门程序</h1>
<%--    <a href="requestParam?username=hh">点击入门程序</a>--%>
    <a href="putSession">putSession</a>
    <a href="getSession">getSession</a>
    <a href="clearSession">clearSession</a>

    </form>
</body>
</html>

controller类代码:

/**
     * 将map值传入session阈中
     * @param model
     * @return
     */
    @RequestMapping(path = "/putSession")
    public String putSession(Model model){
        System.out.println("------putSession执行了-------");
        Map<String,String> map = new HashMap<>();
        //存入到request域对象中
        model.addAttribute("msg","name");

        return "success";
    }

    /**
     * 获取session的值
     * @param modelMap
     * @return
     */
    @RequestMapping(path = "/getSession")
    public String getSession(ModelMap modelMap){
        System.out.println("------getSession执行了-------");
        String msg = (String) modelMap.get("msg");
        System.out.println(msg);
        return "success";
    }

    /**
     * 清除session值
     * @param status
     * @return
     */
    @RequestMapping(path = "/clearSession")
    public String clearSession(SessionStatus status){
        System.out.println("------clearSession执行了-------");
        status.setComplete();
        return "success";
    }

restful编程风格

  • 什么是restful
    是一种设计风格
  • 优点
    结构清晰,易于理解、扩展方便
  • 特性
    资源:网络上的一个具体信息,每个资源有一个URI(统一资源定位符)。获取这个资源,访问他的URI就可以,因此URI为每一个资源的独一无二的识别符
    表现层:把资源呈现出来的形式,叫做它的表现层
    比如,文本可以用txt或者json,xml等格式展现
    状态转化:
    http协议里面,四种请求方式:get,post,put和delete。
    get用来获取资源,post用来新建资源,post用来更新资源,delete用来删除资源
  • 图解
  • javaFX Alert按钮样式_xml_09

  • 普通的方式可以通过请求路径的不同,从而让不同的方法去接受这个请求,而restful风格的设计是路径相同,通过请求方法不同的形式,让不同的方法处理请求,以及将需要传递的参数也放在路径已达到目的。

响应请求的四种方式

响应之后返回值是string类型

/**
     * 响应之后返回string类型
     * @param model
     * @return
     */
    @RequestMapping("/testGetUser")
    public String getUser(Model model){
        System.out.println("---------getUser方法执行了-----------");
        //模拟从数据库中取出user对象
        User user = new User();
        user.setUserName("zhangsan");
        user.setPassword("123");
        user.setAge(12);
        model.addAttribute("user",user);
        return "success";
    }

响应之后返回值是void类型

/**
     * 响应之后返回值是void类型
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping("/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("---------testVoid方法执行了-----------");
        //转发,一次请求
//        request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
        //重定向,两次请求,不能访问WEB-INF下的jsp文件
//        response.sendRedirect(request.getContextPath()+"/response.jsp");
        //解决中文乱码问题
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //直接进行响应
        response.getWriter().print("你好");

    }

响应之后返回值是ModelAndVies类型

/**
     * 响应之后返回值是ModelAndView类型
     * @return
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        System.out.println("---------testModelAndView方法执行了-----------");
        //模拟从数据库中取出user对象
        ModelAndView modelAndView = new ModelAndView();
        User user = new User();
        user.setUserName("zhangsan");
        user.setPassword("123");
        user.setAge(12);

        modelAndView.addObject("user",user);
        modelAndView.setViewName("success");
        return modelAndView;
    }

使用forward和redirect关键字进行页面跳转

注意:使用关键字的方式不会经过视图解析器,因此在路径的填写上需要填写完整路径。
代码示例:

@RequestMapping("/testForward")
    public String testForward() {
        System.out.println("---------testForward方法执行了-----------");
        //转发
//        return "forward:/WEB-INF/pages/success.jsp";
        //重定向
        return "redirect:/response.jsp";
    }

发送ajax请求并响应(数据传输以json格式进行传输)

首先需要导入jackson相关的jar包

<!-- jackson-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.8</version>
    </dependency>


    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.8</version>
    </dependency>

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

发送ajax请求代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>index</title>

<%--    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script>--%>

    <script src="js/jquery-min.js"></script>
    <script>
        //页面加载绑定单击事件
        $(function () {
                $("#btn").click(function () {
                // alert("发送请求222")
                    //发送ajax请求
                    $.ajax({
                        url:"user/testAjax",
                        contentType:"application/json;charset=utf-8",
                        data:'{"userName":"Tom","password":"123","age":1}',
                        dataType:"json",
                        type:"post",
                        success:function (data) {
                            alert(data)
                            alert(data.userName)
                        }
                    })
            })
        })
    </script>

</head>
<body>
 
    <button id="btn">发送ajax请求</button>


</body>
</html>

响应请求代码:

/**
     * 响应ajax请求
     * 通过@RequestBody获取请求体,并塞入user中
     * @ResponseBody将返回的uer转化为json格式
     * @param user
     * @return
     */
    @RequestMapping(value = "/testAjax",method = RequestMethod.POST)
    @ResponseBody
    public User testAjax(@RequestBody User user) {
        System.out.println("---------testAjax方法执行了-----------");
        System.out.println(user.toString());
        user.setUserName("Jerry");
        return user;
    }

文件上传

传统方式

文件上传的必要前提

1)form表单的enctype取值为multipart/form-data(将请求内容分部分)

2)method的属性为post

3)提供一个文件选择域

文件上传原理

javaFX Alert按钮样式_spring_10


javaFX Alert按钮样式_xml_11


传统文件上传方式需借助第三方组组件实现文件上传

javaFX Alert按钮样式_javaFX Alert按钮样式_12


主要代码

  • 导入的jar包
<!-- 第三方jar包实现文件上传 -->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>


    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
  • jsp文件代码:
<body>
    <form action="testFile" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br><br>
        <input type="submit" value="上传">
    </form>
</body>
  • 控制层代码:
@RequestMapping("/testFile")
    public String testFile(HttpServletRequest request) throws Exception {
        System.out.println("--------testFile方法执行了-------");
        //上传路径
        String path = request.getSession().getServletContext().getRealPath("/upload");
        System.out.println(path);
        File file = new File(path);
        //判断文件夹是否存在,若不存在,则创建一个
        if(!file.exists()){
            file.mkdir();
        }
        //解析上传文件,获取上传资源
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        //解析request
        List<FileItem> fileItems = upload.parseRequest(request);

        for (FileItem item:fileItems){
            //判断当前item是否为文件上传项
            if(item.isFormField()){

            }else {
                //获取上传文件的名称
                String filename = item.getName();
                String uuid = UUID.randomUUID().toString().replace("-","");
                filename = uuid+"-"+filename;

                //完成文件上传
                item.write(new File(path,filename));
                //删除临时文件
                item.delete();
            }
        }
        return "success";
    }

springmvc文件上传

实现原理:

springmvc框架为我们提供了一个文件解析器,帮助我们解析request,然后通过MultipartFile的transfor方法实现文件上传。

javaFX Alert按钮样式_mvc_13


注意点:

1)文件解析器(CommonsMultipartResolver)的bean 的id必须为multipartResolver

2)MultipartFile 类名字需要与form表单中<input type="file" name="upload">的name名称相一致

代码示例:

  • 文件解析器配置:
<!--配置文件解析器,id必须为multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"></property>
    </bean>
  • 控制层代码:
/**
     * @param request
     * @param upload  需要与表单中文件名字相同
     * @return
     * @throws Exception
     */
    @RequestMapping("/testSpringMvcFile")
    public String testSpringMvcFile(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("--------testSpringMvcFile1方法执行了-------");
        //上传路径

        String path = request.getSession().getServletContext().getRealPath("/upload");
        System.out.println(path);
        File file = new File(path);
        //判断文件夹是否存在,若不存在,则创建一个
        if (!file.exists()) {
            file.mkdir();
        }

        //解析request

        //获取上传文件的名称
        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "-" + filename;

        //完成文件上传
        upload.transferTo(new File(path,filename));

        return"success";
    }

跨服务器实现文件上传

javaFX Alert按钮样式_javaFX Alert按钮样式_14


javaFX Alert按钮样式_xml_15

springmvc的异常处理

异常处理思路

javaFX Alert按钮样式_xml_16


controller调用service,service调用dao,异常都是向上抛出的,最终有前端处理器找到异常处理器进行异常处理

springmvc异常处理示例小代码

  • 步骤
    1)编写自定义异常类(做提示信息)
    2)编写异常处理器
    3)配置异常处理器(跳转到提示页面)

示例代码:

  • index.jsp
<%--
  Created by IntelliJ IDEA.
  User: AIR
  Date: 2020/1/9
  Time: 15:13
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>方法执行</h1>
    <a href="error/testError">异常执行</a>
</body>
</html>
  • error.jsp
<%--
  Created by IntelliJ IDEA.
  User: AIR
  Date: 2020/1/9
  Time: 15:13
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>异常页面</h1>
    ${error}
</body>
</html>
  • 自定义异常类
package com.hwh.entity;

/**
 * @Description 自定义异常类
 * @Author hwh
 * @Date 2020/1/9 15:32
 **/
public class SysException extends Exception {
    private String message;

    public SysException(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
  • 异常处理器类
package com.hwh.exceprion;

import com.hwh.entity.SysException;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Description 异常处理器
 * @Author hwh
 * @Date 2020/1/9 15:34
 **/
@Controller
public class ExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        SysException sysException = null;
        if(e instanceof SysException){
            sysException = (SysException)e;
        }else {
            sysException = new SysException("系统正在维护");
        }
        ModelAndView mv = new ModelAndView();
        mv.addObject("error", sysException.getMessage());
        mv.setViewName("error");
        return mv;
    }
}
  • 控制层类
package com.hwh.controller;

import com.hwh.entity.SysException;
import org.omg.CORBA.SystemException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Description TODO
 * @Author hwh
 * @Date 2020/1/9 15:14
 **/
@Controller
@RequestMapping("/error")
public class ErrorController {

    @RequestMapping("/testError")
    public String testError() throws SysException {
        System.out.println("--------testError方法执行了--------");
        try {
            int i= 10/0;
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException("发生错误");
        }
        return "error";
    }
}

springmvc拦截器

spring mvc中的拦截器类似于servlet中的过滤器filter,用于对处理器进行预处理和后处理。我们要自定义拦截器,必须实现HandlerInterceptor接口

拦截器和过滤器的区别

1)过滤器是servlet规范中的一部分,任何java web工程都可以使用

过滤器是springmvc框架自己的,只有使用了springmvc框架的工程才能使用

2)过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。

拦截器只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的

总结:拦截器能做的事,过滤器全部能做,过滤器能做的事,拦截器不一定能做。

拦截器链:

其实就是多个拦截器,一个拦截器执行完后去执行下一个

javaFX Alert按钮样式_spring_17

springmvc拦截器入门小程序

主要代码:

  • index.jsp
<body>
    <h1>拦截器</h1>
    <a href="interceptor/testInterceptor">拦截器</a>
</body>
  • success.jsp
<body>
    <h1>方法执行成功</h1>
    <% System.out.println("---------success.jsp执行了------------"); %>

</body>
  • error.jsp
<body>
    <h1>错误页面</h1>
</body>
  • InterceptorController.java
package com.hwh.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Description TODO
 * @Author hwh
 * @Date 2020/1/9 19:20
 **/
@Controller
@RequestMapping("/interceptor")
public class InterceptorController {

    @RequestMapping("/testInterceptor")
    public String testInterceptor(){
        System.out.println("------------testInterceptor方法执行了------------");

        return "success";
    }
}
  • Interceptor.java(重写拦截器方法)
package com.hwh.utils;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Description 自定义拦截器类
 * @Author hwh
 * @Date 2020/1/9 19:24
 **/
public class Interceptor implements HandlerInterceptor {

    /**
     * 预处理,在contoller方法前执行
     * return true方形,执行下一个拦截器方法,若没有,执行controller中的方法
     * return false 不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("-----------拦截器预处理方法执行了--------------");
        return true;
    }

    /**
     * 在controller方法之执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("-----------拦截器后处理方法执行了--------------");
        //跳到error页面之后就不会再跳到success的页面了,但是success仍会执行
//        request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * 在最终执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("-----------拦截器最终处理方法执行了--------------");
    }
}
  • springmvc.xml
<!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--配置要拦截的方法-->
            <mvc:mapping path="/interceptor/**"/>
            <!--配置不拦截的方法-->
<!--            <mvc:exclude-mapping path=""/>-->
            <bean class="com.hwh.utils.Interceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  • 运行结果:

    配置多个拦截器
<!--配置拦截器-->
    <mvc:interceptors>

        <mvc:interceptor>
            <!--配置要拦截的方法-->
            <mvc:mapping path="/interceptor/**"/>
            <!--配置不拦截的方法-->
<!--            <mvc:exclude-mapping path=""/>-->
            <bean class="com.hwh.utils.Interceptor"></bean>
        </mvc:interceptor>

        <!--配置第二个拦截器-->
        <mvc:interceptor>
            <!--配置要拦截的方法-->
            <mvc:mapping path="/interceptor/**"/>
            <!--配置不拦截的方法-->
            <!--            <mvc:exclude-mapping path=""/>-->
            <bean class="com.hwh.utils.Interceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  • 运行结果: