SpringMVC基本概念

在这里插入图片描述

MVC设计模型

  • Model模型 JavaBean
  • View视图 JSP
  • Controller控制器 Servlet

SpringMVC和Strut2的优劣分析

共同点

  • 它们都是表现层框架,都是基于 MVC 模型编写的。
  • 它们的底层都离不开原始 ServletAPI。
  • 它们处理请求的机制都是一个核心控制器。

区别

  • Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
  • Spring MVC 是基于方法设计的,而 Struts2 是基于类
  • Struts2 每次执行都会创建一个动作类。所以 Spring MVC 会稍微比 Struts2 快些。
  • Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便
  • (JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)
  • Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提升,尤其是 struts2 的表单标签,远没有 html 执行效率高

入门案例

在这里插入图片描述

搭建环境

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
      <spring.version>5.0.2.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

执行流程

在这里插入图片描述

在这里插入图片描述

入门案例的执行流程

  1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,
    就会加载springmvc.xml配置文件
  2. 开启了注解扫描,那么HelloController对象就会被创建
  3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解
    找到执行的具体方法
  4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件(方法的返回值就是指定目录下的JSP文件名)
  5. Tomcat服务器渲染页面,做出响应

springmvc.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!--开启注解扫描-->
    <context:component-scan base-package="com.atgw"/>

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

    <!--开启注解SpringMVC框架注解支持-->
    <mvc:annotation-driven/>

</beans>

web.xml

<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>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup><!--在开启服务器的时候就加载上面的springmvc.xml-->
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

ControllerHolle程序

//控制器类
@Controller
public class HelloController  {

    @RequestMapping(path = "/hello")
    public String sayHello(){
        System.out.println("Hello StringMVC");
        return "success";
    }
}

RequestMapping注解

RequestMapping注解在类和类下的方法上都有的时候,在请求的路径上要同时写全路径

//控制器类
@Controller
@RequestMapping(path = "/user")
public class HelloController  {

    @RequestMapping(path = "/testRequestMapping")
    public String testRequestMapping(){
        System.out.println("测试RequestMapping");
        return "success";
    }
}

下面要写全路径(类的加上方法的path)

    <a href="user/testRequestMapping">RequestMapping超链接</a>

作用

  1. value :用于请求指定的url,它和path属性的作用是一样的

  2. method:用于指定请求方式(Get,Post等)

        @RequestMapping(value = "/testRequestMapping",method = {RequestMethod.POST})
        public String testRequestMapping(){
            System.out.println("测试RequestMapping");
            return "success";
        }
    
  3. params:用于指定限定请求参数的条件,它支持简单的表达式,要求请求参数的key和value必须和配置的一模一样

        @RequestMapping(value = "/testRequestMapping",params = {"username=admin","password"})
        public String testRequestMapping(){
            System.out.println("测试RequestMapping");
            return "success";
        }
    
        <a href="user/testRequestMapping?username=admin&password=123">RequestMapping超链接</a>
    
  4. 发送请求中必须包含指定的请求头


请求参数的绑定

在请求的路径中传入参数,我们可以在控制器类中的方法中写入参数并获取(底层是通过反射实现的)

ParamController程序

@Controller
@RequestMapping(path = "/user")
public class ParamController {

    @RequestMapping(path = "/testParam")
    public String testParam(String username,String password){
        System.out.println("用户名:"+username);
        System.out.println("密码:"+password);
        return "success";
    }
}

param.jsp

    <a href="user/testParam?username=yiersansiwu&password=456321">Param请求</a>

封装到JavaBean对象中

User

public class User {

    private String uname;
    private Integer age;
}

Account

public class Account implements Serializable {

    private String username;
    private String password;
    private Double money;

    //引用类型
    private User user;
}

param.jsp

     <form action="user/saveAccount" method="post">
         <%--下面的name属性要和封装的JavaBean对象的属性名一致--%>
         用户名:<input type="text" name="username"><br/>
         密码:<input type="text" name="password"><br/>
             金额:<input type="text" name="money"><br/>
             用户姓名:<input type="text" name="user.uname"><br/>
             用户年龄:<input type="text" name="user.age"><br/>
         <input type="submit" value="提交"><br/>
     </form>

配置中文乱码的过滤器

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>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

封装集合类型

Account

public class Account implements Serializable {

    private String username;
    private String password;
    private Double money;

    private List<User> list;
    private Map<String,User> map;
}

param.jsp

    <form action="user/saveAccount" method="post">
        <%--下面的name属性要和封装的JavaBean对象的属性名一致--%>
        用户名:<input type="text" name="username"><br/>
        密码:<input type="text" name="password"><br/>
        金额:<input type="text" name="money"><br/>
            用户姓名1:<input type="text" name="list[0].uname"><br/>
            用户年龄1:<input type="text" name="list[0].age"><br/>
            用户姓名2:<input type="text" name="map['one'].uname"><br/>
            用户年龄2:<input type="text" name="map['one'].age"><br/>
        <input type="submit" value="提交"><br/>
    </form>
Account{username='gao123', password='123456', money=999.0, list=[User{uname='熊大', age=9}], map={one=User{uname='熊二', age=8}}}

自定义类型转换器

先创建一个类型转换器(实现Converter<String, Date>接口)

public class StringToDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        //判断是否为空
        if (s == null){
            throw new RuntimeException("您还没有传入数据!");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        try {
            //字符串转换成日期
             return df.parse(s);
        } catch (Exception e) {
            throw new RuntimeException("数据类型转换出现错误!");
        }
    }
}

springmvc.xml配置自定义类型转换器

<!--配置自定义类型转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.atgw.utils.StringToDateConverter"></bean>
            </set>
        </property>
    </bean>

    <!--开启注解SpringMVC框架注解支持-->
    <mvc:annotation-driven conversion-service="conversionService"/><!--配置类型转换器生效-->

获取Servlet原生的API

    //获取servlet原生的API
    @RequestMapping(path = "/testServlet")
    public String testServlet(HttpServletRequest request, HttpServletResponse response){
            System.out.println(request);

        HttpSession session = request.getSession();
        System.out.println(session);

        ServletContext servletContext = session.getServletContext();
        System.out.println(servletContext);

        System.out.println(response);

        return "success";
    }
    <a href="user/testServlet">Servlet原生的API</a>

常用注解

RequestParam注解

@Controller
@RequestMapping("/anno")
public class AnnoController {

    @RequestMapping("/testRequestParam")
    public String testRequestParam(@RequestParam(name = "name") String username){
        System.out.println(username);
        return "success";
    }
}
    <<a href="anno/testRequestParam?name=高先生">Anno链接</a>

当请求的路径中的参数name和控制器类的方法获取的参数名不一致时,我们可以添加@RequestParam(name = "name")注解来配置


RequestBody注解

  • 用于获取请求体的内容,直接使用得到的是key=value&key=value结构的数据

  • 因为Get请求没有请求体,所以Get请求不适用

    @RequestMapping("/testRequestBody")
    public String testRequestBody(@RequestBody String body){
        System.out.println(body);
        return "success";
    }
    <form action="anno/testRequestBody" method="post">
        用户姓名:<input type="text" name="username"><br/>
        用户年龄:<input type="text" name="age"><br/>
        <input type="submit" value="提交"><br/>
    </form>
结果:
username=gao123&age=12

PathVaribale注解

Restful风格的URL

一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制

  1. 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
  2. restful风格的URL优点
    • 结构清晰
    • 符合标准
    • 易于理解
    • 扩展方便
【GET】 /users # 查询用户信息列表

【GET】 /users/1001 # 查看某个用户信息

【POST】 /users # 新建用户信息

【PUT】 /users/1001 # 更新用户信息(全部字段)

【PATCH】 /users/1001 # 更新用户信息(部分字段)

【DELETE】 /users/1001 # 删除用户信息
    @RequestMapping("testRequestVariable/{sid}")
    public String testPathVariable(@PathVariable(name = "sid") String id){
        System.out.println(id);
        return "success";
    }
    <a href="anno/testRequestVariable/10">RequestVariable注解</a>

RequestHeader注解

获取请求头的值

    //获取RequestHeader注解中value值对应的请求头
    @RequestMapping("testRequestHeader")
    public String testRequestHeader(@RequestHeader(value = "accept") String header){
        System.out.println(header);
        return "success";
    }
    <a href="anno/testRequestHeader">testRequestHeader注解</a>
结果:
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9

CookieValue注解

获取Cookie的值

    //获取Cookiev值
    @RequestMapping("testCookieValue")
    public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookie){
        System.out.println(cookie);
        return "success";
    }
    <a href="anno/testCookieValue">testCookieValue注解</a>
结果:
5800F99C212F2A64740BB9B558ED6803

ModelAttribute注解

作用

  • 出现在方法上:表示当前方法会在控制器方法执行前线执行
  • 出现在参数上:获取指定的数据给参数赋值。

应用场景

  • 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
    <form action="anno/testModelAttribute" method="post">
        用户名:<input type="text" name="uname"><br/>
        年龄:<input type="text" name="age"><br/>
        <input type="submit" value="提交">
    </form>

有返回值

    @RequestMapping(value = "/testModelAttribute")
    public String testModelAttribute(User user){
        System.out.println("testModelAttribute........");
        System.out.println(user);
        return "success";
    }

    //该方法会先执行
    @ModelAttribute
    public User showUser(String uname){
        System.out.println("showUser方法执行了");
        //通过User查询数据库(模拟)
        User user = new User();
        user.setUname(uname);//uname是从表单中获取的
        user.setAge(20);//如果表单没有此项,则会采用从数据库中获取的
        user.setDate(new Date());
        return user;
    }

无返回值

    @RequestMapping(value = "/testModelAttribute")
    public String testModelAttribute(@ModelAttribute("123") User user){
        System.out.println("testModelAttribute........");
        System.out.println(user);
        return "success";
    }

    //该方法会先执行
    @ModelAttribute
    public void showUser(String uname, Map<String,User> map){
        System.out.println("showUser方法执行了");
        //通过User查询数据库(模拟)
        User user = new User();
        user.setUname(uname);//uname是从表单中获取的
        user.setAge(20);//如果表单没有此项,则会采用从数据库中获取的
        user.setDate(new Date());
        map.put("123",user);
    }
结果:
showUser方法执行了
testModelAttribute........
User{uname='gao123', age=12, date=Fri Feb 05 19:48:36 CST 2021}

SessionAttributes注解

用于多次执行控制器方法间的参数共享

@Controller
@RequestMapping("/anno")
@SessionAttributes(value = {"msg"})//把msg=美美存入到Session域
public class AnnoController {  
    
@RequestMapping(value = "/testSessionAttributes")
    public String testSessionAttributes(Model model){
        //底层会存储到request域对象中
        model.addAttribute("msg","美美");
        return "success";
    }
}
 <a href="anno/testSessionAttributes">SessionAttributes注解</a>

登陆成功页面获取域对象的值

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
   
${requestScope}<br/>
    ${sessionScope}

Session域中的数据同样也可以在其他的方法中获取

    //从Session域获取值
    @RequestMapping(value = "/getSessionAttribute")
    public String getSessionAttribute(ModelMap modelMap){
        System.out.println(modelMap.get("msg"));
        return "success";
    }

执行方法的响应

返回类型是void

因为返回类型是void,所以就不能再对应指定目录下的响应文件了

采取下面的方法

  • 请求转发(一次请求)

        @RequestMapping("/testVoid")
        public void testVoid(HttpServletRequest request, HttpServletResponse response)throws Exception{
            //编写请求转发的程序
            request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
            return;
        }
    
        <a href="user/testVoid">testVoid方法</a>
    
  • 重定向(两次请求)

    //重定向(WEB-INF里面的内容不能直接请求)
    response.sendRedirect(request.getContextPath()+"/index.jsp");
    
  • 直接响应

        @RequestMapping("/testVoid")
        public void testVoid(HttpServletRequest request, HttpServletResponse response)throws Exception{
            //编写请求转发的程序
            //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
    
            //重定向(WEB-INF里面的内容不能直接请求)
    //        response.sendRedirect(request.getContextPath()+"/index.jsp");
    //        return;
    
            //设置中文乱码
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            //直接响应
            response.getWriter().print("你好");
            return;
        }
    

使用关键字forwardredirect进行页面跳转

使用上面的方式进行页面跳转时,就不使用视图解析器对象

    //使用关键字forward和redirect来进行页面跳转
    @RequestMapping("/testForwardOrRedirect")
    public String testForwardOrRedirect(){
        //请求转发
//        return "forward:/WEB-INF/pages/success.jsp";

        //重定向(重定向不能访问WEB-INF里面的内容)
        return "redirect:/index.jsp";
    }
    <a href="user/testForwardOrRedirect">testForwardOrRedirect</a>

过滤静态资源

我们在web.xml文件中配置了前端控制器,它会对所有的资源进行拦截过滤,导致我们的静态资源(webapp目录下的css,js,images目录)不能正常使用,所以我们在springmvc.xml文件中对前端控制器进行配置,让其对静态资源不进行拦截

springmvc.xml文件

    <!--前端控制器,哪些静态资源不拦截(webapp目录下的资源)-->
    <mvc:resources mapping="/js/**/" location="/js/"></mvc:resources>
    <mvc:resources mapping="/css/**/" location="/css/"></mvc:resources>
    <mvc:resources mapping="/images/**/" location="/images/"></mvc:resources>

下面静态资源可以正常访问

    <script src="js/jquery.min.js"></script>

    <script>
        //页面加载
        $(function () {
            $("#btn").click(function () {
                alert("Hello btn");
            });
        });
    </script>

返回类型是ModelAndView类型

    //返回值是ModelAndView类型
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        //创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        //模拟从数据库中查询出对象
        User user = new User();
        user.setUsername("O(∩_∩)O哈哈~");
        user.setAge(20);
        user.setPassword("234");

        //把user对象存储到mv对象中,也会把user对象存入到request对象
        mv.addObject("user",user);

        //跳转到哪个页面
        mv.setViewName("success");

        return mv;
    }
    <a href="user/testModelAndView">testModelAndView</a>

上面的操作也会把user对象存入到request对象

success.jsp页面

    ${requestScope.user}<br/>
    ${requestScope.user.username}<br/>
    ${requestScope.user.password}<br/>
    ${requestScope.user.age}<br/>

响应Json数据之发送Ajax请求

response.jsp

    <script src="js/jquery.min.js"></script>

    <script>
        //页面加载
        $(function () {
            $("#btn").click(function () {
                //发送Ajax请求
                $.ajax({
                    //编写json格式,设置属性和值
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"向飒飒","password":"123","age":30}',
                    dataType:"json",
                    type:"post",
                    success:function (data) {
                        //data服务器响应的json数据

                    }
                });
            });
        });
    </script>
    //模拟异步请求响应
    @RequestMapping("/testAjax")
    public void testAjax(@RequestBody String body){//获取请求体
        System.out.println("testAjax方法执行了");
        System.out.println(body);
    }

后台响应数据之后(封装修改)做出回传响应

    //模拟异步请求响应
    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){//获取请求体
        System.out.println("testAjax方法执行了");
        //客户端发送ajax请求,传的是json字符串,后端把json字符串封装到user对象中
        System.out.println(user);
        //作出相应,模拟查询数据库,修改数据之后返回
        user.setUsername("山地车");
        user.setAge(50);
        //返回相应
        return user;
    }

ajax做出响应

                    success:function (data) {
                        //data服务器响应后端的json数据
                        alert(data.toString());
                        alert(data.username);
                        alert(data.password);
                        alert(data.age);
                    }

文件上传

原理

在这里插入图片描述


传统方式

文件上传坐标

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
    <h3>文件上传</h3>

    <a></a>
    <form action="user/fileupload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br/>
        <input type="submit" value="上传">
    </form>
    //文件上传
    @RequestMapping(value = "/fileupload1")
    public String fileupload1(HttpServletRequest request) throws Exception {
        System.out.println("文件上传");

        //使用fileupload组件完成文件上传
        //上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        System.out.println(path);
        //判断该路径是否存在
        File file = new File(path);
        if (!file.exists()){
            //创建该文件夹
            file.mkdirs();
        }

        //解析request对象,获取上传文件项
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        //解析request
        List<FileItem> items = upload.parseRequest(request);
        //遍历
        for (FileItem item : items){
            //进行判断,当前item对象是否是文件上传项
            if (item.isFormField()){
                //说明是普通表单项
            }else {
                //说明上传文件项
                //获取上传文件名
                String filename = item.getName();

                //把文件名设置成唯一值(使用UUID)
                String uuid = UUID.randomUUID().toString().replace("-", "");
                filename = uuid + "_" +filename;

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

springmvc方式

    <h3>springmvc方式文件上传</h3>

    <a></a>
    <form action="user/fileupload2" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br/>
        <input type="submit" value="上传">
    </form>
    //springmvc方式文件上传
    @RequestMapping(value = "/fileupload2")
    public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("SpringMVC文件上传");

        //使用fileupload组件完成文件上传
        //上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        System.out.println(path);
        //判断该路径是否存在
        File file = new File(path);
        if (!file.exists()){
            //创建该文件夹
            file.mkdirs();
        }
        
        //获取上传文件名
        String filename = upload.getOriginalFilename();
        //把文件名设置成唯一值(使用UUID)
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "_" +filename;
        //完成文件上传
        upload.transferTo(new File(path,filename));

        return "success";
    }

springmvc跨服务器上传文件

坐标

<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
    <h3>跨服务器方式文件上传</h3>
    <a></a>
    <form action="user/fileupload3" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br/>
        <input type="submit" value="上传">
    </form>
    //跨服务器方式文件上传
    @RequestMapping(value = "/fileupload3")
    public String fileupload3(MultipartFile upload) throws Exception {
        System.out.println("跨服务器文件上传");

        //定义上传文件的服务器路径
        String path = "http://localhost:9090/uploads/";


        //获取上传文件名
        String filename = upload.getOriginalFilename();
        //把文件名设置成唯一值(使用UUID)
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "_" +filename;

        //创建客户端对象
        Client client = Client.create();
        //和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);
        //完成文件上传
        webResource.put(upload.getBytes());

        return "success";
    }

SpringMVC的异常处理

在这里插入图片描述

自定义异常类

public class SysException extends Exception {

    private String message;

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

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

自定义异常处理器

public class SysExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) {
        //获取到异常对象
        SysException e = null;
        if (ex instanceof SysException){
            e = (SysException)ex;
        }else {
            e = new SysException("系统正在维护...");
        }
        //创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());//获取错误信息
        mv.setViewName("error");
        return mv;
    }

配置异常处理器

    <!--配置异常处理器-->
    <bean id="sysExceptionResolver" class="com.atgw.exception.SysExceptionResolver">
    </bean>

@Controller
@RequestMapping(value = "/user")
public class UserController {

    @RequestMapping("/testException")
    public String testException() throws Exception{
        System.out.println("testException执行了");

        try {
            //模拟异常
            int a = 10/0;
        }catch (Exception e){
            //打印异常信息
            e.printStackTrace();
            //抛出自定义异常信息
            throw new SysException("查询所有用户出现错误了");
        }
        return "success";
    }
}
    <a href="user/testException">异常处理</a>

友好提示页面error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
    ${errorMsg}

拦截器

SpringMVC拦截器类似于Servlet开发中的过滤器,用于处理器进行预处理和后处理

  • 过滤器对所有的资源都可以拦截
  • 拦截器只能对Controller进行拦截

MyInterceptor1自定义拦截器

//自定义拦截器
public class MyInterceptor1 implements HandlerInterceptor {

    /*
    预处理,controller方法执行前
    return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
    return false 不放行,权限检查
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1拦截器执行了...前");

        //不放行时,请求转发到error.jsp页面
        //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);

        return true;
    }

    /*
    controller方法执行后,success.jsp方法执行前
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("controller方法执行后,success.jsp方法执行前");

        //如果在这里进行页面跳转的话,比如跳转到error.jsp页面,success.jsp页面会执行,但是不会跳转到success.jsp
    }

    /*
    success.jsp页面之后
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("success.jsp页面之后");
    }
}

springmvc.xml配置拦截器

    <!--配置拦截器-->
    <mvc:interceptors>
        <!--配置第一个拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体方法-->
            <mvc:mapping path="/user/*"/><!--控制类里面的方法-->
            <!--不要拦截的方法-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置拦截器对象(自定义的拦截器或者已经提供的)-->
            <bean class="com.atgw.interceptor.MyInterceptor1"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

index.jsp

    <h3>拦截器</h3>

    <a href="user/testInterceptor">拦截器</a>

UserController程序

@Controller
@RequestMapping(value = "/user")
public class UserController {

    @RequestMapping("/testInterceptor")
    public String testInterceptor() {
        System.out.println("testInterceptor执行了");
        return "success";
    }
}
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐