SpringMVC从入门到掌握

SpringMVC从入门到掌握

1. SpringMvc的概述
  • Spring MVC为展现层提供的基于MVC设计理念的优秀Web框架,是目前最主流的MVC框架之一。
  • Spring3.0后全面超越了Struts2,称为最优秀的MVC框架。
  • Spring MVC通过一套MVC注解,让POJO称为处理请求的控制器,无需实现任何接口。
  • 支持REST风格的Web请求。采用了松散耦合可插拔组件结构,比其它MVC框架更具扩展性和灵活性。
2. SpringMvc的搭建
  1. 导入依赖

    <dependency>
    	    <groupId>org.springframework</groupId>
    	    <artifactId>spring-webmvc</artifactId>
    	    <version>5.1.1.RELEASE</version>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    	<dependency>
    	    <groupId>javax.servlet</groupId>
    	    <artifactId>javax.servlet-api</artifactId>
    	    <version>4.0.1</version>
    	    <scope>provided</scope>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
    	<dependency>
    	    <groupId>javax.servlet</groupId>
    	    <artifactId>jstl</artifactId>
    	    <version>1.2</version>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    	<dependency>
    	    <groupId>com.fasterxml.jackson.core</groupId>
    	    <artifactId>jackson-databind</artifactId>
    	    <version>2.9.7</version>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
    	<dependency>
    		<groupId>org.hibernate.validator</groupId>
    		<artifactId>hibernate-validator</artifactId>
    		<version>6.0.13.Final</version>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
    	<dependency>
    		<groupId>javax.validation</groupId>
    		<artifactId>validation-api</artifactId>
    		<version>2.0.1.Final</version>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
    	<dependency>
    		<groupId>org.jboss.logging</groupId>
    		<artifactId>jboss-logging</artifactId>
    		<version>3.3.2.Final</version>
    	</dependency>
    
  2. 配置xml文件

     <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
               <!-- SpringMVC配置文件路径 -->
            <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>
    <!-- 注意:如果没有配置 init-param 设置文件路径,SpringMvc默认回去WEB-INF下查询 servlet-nameservlet.xml -->
    
  3. 创建处理类

    注解

      @Controller // 修饰类为一个控制器
      public class HelloWorld { 
        @RequestMapping("/hello") // 修饰方法(或类)的请求路径
        public String hello(){
            System.out.println("hello spring mvc");
            return "hello"; // 视图
        }
      }
    
      <!-- 配置Spring MVC自动扫描的路径 -->
      <context:component-scan base-package="com.*.controller" />
       <!-- 配置视图解析器 将视图返回字符串解析到:/WEB-INF/view/返回值.jsp 下-->
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 视图前缀 -->
        <property name="prefix" value="/WEB-INF/view/" />
        <!-- 视图后置 -->
        <property name="suffix" value=".jsp" />
      </bean>
    

    接口

      public class HelloWorld implements Controller{
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            System.out.println("HelloWorld");
            return new ModelAndView("hello"); // 视图
        }
      }
    
      <!-- name:代表访问路径 class:指定控制器类 -->
      <bean name="/helloworld" class="com.znsd.controller.HelloWorld" />
    

    两种方式,推荐使用注解 (不是必须,分情况而待)

3. SpringMvc的常用注解总结
  • @Component:一个普通的Bean类。

  • @Repository :用于标注持久层DAO类

  • @Service :用于标注业务层类

  • @Controller :用于标注控制器类

  • @RequestMapping:

    • 类定义处:提供初步的映射信息,为该类下所有请求方法添加前缀。

    • 方法定义处:提供进一步的映射信息,提供方法的请求路径。

        @Controller
        @RequestMapping("world") // 类似Struts2的@Namespace(命名空间)
        public class HelloWorld { 
          @RequestMapping("/hello")
          public String hello(){
              System.out.println("hello spring mvc");
              return "hello";
          }
        }
      
      1. @RequestMapping 的 value、method、params及heads分别表示请求url,请求方法,请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可以让请求更加精确化。

      2. 在@RequestMapping 中 还支持 Ant风格的URL。

        • ?:匹配文件中一个字符。

        • *:匹配文件中任意字符。

        • **:匹配多层路径。

            /user/*/create:匹配/user/aaa/create,/user/bbb/crate
            /user/**/create:匹配/user/create,/user/aaa/bbb/create
            /user/create??:匹配/user/createaa,/user/createbb 
          
  • @PathVariable:URL模版方式

      // @PathVariable:用来映射URL中的占位符。映射的变量名必须和占位符中的名称一致。
      @RequestMapping("/delete/{userid}")
      public String delete(@PathVariable("userid")int userid) {
        System.out.println("userid=" + userid);
        return "hello";
      }
    
  • @RequestParam:获取请求参数

     // @RequtParam:获取页面传递过来的参数,GET和POST都支持。
     @RequestMapping("/testRequestParam")
     public String testRequestParam(@RequestParam("username")String username, @RequestParam("age")int age){
        System.out.println("username=" + username);
        System.out.println("age=" + age);
        return "hello";
      }
    

    @RequestParam 还有三个属性

    • value:指定参数的名称
    • required:指定参数是否为必填 (boolean)
    • defaultValue:指定参数的默认值
  • @RequestHeader:获取请求头内容

      // 请求头包含了若干的属性,用来获取客户端的信息。通过@RequestHeader可以用来获取请求头中的信息
      @RequestMapping("/testRequestHeader")
      public String testRequestHeader(@RequestHeader("Accept-Language") String language){
        System.out.println("language=" + language);
        return "hello";
      }
    
  • @CookiValue:获取客户端Cookie

      // @CookieValue:用来获取客户端Cookie信息。
      @RequestMapping("/testCookieValue")
      public String testCookieValue(@CookieValue("JSESSIONID")String sessionid){
        System.out.println("sessionid=" + sessionid);
        return "hello";
      }
    
  • @ResponseBody:标识为Json返回

    • 需要导入依赖

      <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
      	<dependency>
      	    <groupId>com.fasterxml.jackson.core</groupId>
      	    <artifactId>jackson-databind</artifactId>
      	    <version>2.9.7</version>
      	</dependency>
      
      @ResponseBody
      @RequestMapping(value="/testJackson",method=RequestMethod.GET)
      public Student testJackson() {
      	User user = new User();
      	user.setName("李相如");
      	return user;
      }
      
4. 实体对象绑定请求参数
<!-- name必须和对象属性名一至 -->
<form action="world/user/create" method="post">
    姓名:<input type="text" name="name"><br>
    密码:<input type="text" name="pass"><br>
    年龄:<input type="text" name="age"><br>
    <input type="submit" value="提交" />
 </form>
  public class User {
    private String name;
    private String pass;
    private int age;
  }
  // Spring MVC会直接将页面元素和实体对象进行匹配,自动转换为实体对象.并且支持级联属性。如address.city等。
  @RequestMapping(value = "/user/create", method = RequestMethod.POST)
  public String createUser(User user) {
    System.out.println(user.toString());
    return "hello";
  }
5. 处理数据模型

Spring MVC提供一下几种途径返回模型数据:

  • ModeAndView:将处理方法的返回类型设置为ModeAndView,方法体即可通过该模型对象添加模型数据。

  • 控制器处理方法如果返回ModelAndView,即包含视图信息,也包含模型信息。

  • 构造方法:提供了多种构造方法的重载

  • 添加模型数据:

    • ModelAndView addObject(String attributeName, Object attributeValue);
    • ModelAndView addAllObjects(Map modelMap) ;
  • 添加视图

    • void setView(View view);

    • void setViewName(String viewName);

        @RequestMapping("/testModelAndView")
        public ModelAndView testModelAndView(){
          ModelAndView modelAndView = new ModelAndView("hello");
          //添加单个值
          modelAndView.addObject("h","Hello Spring MVC");     
          return modelAndView;
        }
      
  • Map及Model形参:当形参为Map,Model,ModelMap时,处理方法返回时,Map中的数据会自动添加到模型中。

    • Spring MVC在内部使用了一个Model接口存储模型数据。

    • Spring MVC在调用方法前会创建一个隐含的模型对象作为数据模型的存储容器。如果传入的参数为Map或者Model类型,SpringMVC会自动将对象保存到模型数据中。

       @RequestMapping("/testMap")
        public String testMap(Map<String,Object> map){
          map.put("mapdata", "map data");
          return "hello";
        }
      
  • @SessionAttributes:将模型中的某个属性存储到Session中,以便多个请求之间共享这个属性。

    • 如果希望在多个请求之间共享某个模型的数据,则可以在控制器类上标注一个@SessionAttributes,SpringMVC会将对应的属性存储到Session中。

    • @SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些类型放到Session中。

      • @SessionAttributes(types=User.class) :将隐含模型中所有类型为User属性添加到Session中。

      • @SessionAttributes(value={“user1”,“user2”}):将user1对象和user2放入Session中。

         // 保存到Session中
         @SessionAttributes("user")
          @Controller
          @RequestMapping("world")
          public class HelloWorld {
            @RequestMapping("/testSession")
            public String testSession(Map<String,Object> map){
                User user = new User();
                user.setUsername("zhangsan");
                user.setUserpass("123");
                user.setAge(20);
                map.put("user", user);
                return "hello";
            }
          }
        
    • @SessionAttributes只能用来修饰类。

  • @ModelAttribute:方法形参标记该注解后,形参对象就会放到模型中。

    • 在方法定义上定义@ModelAttribute注解:

      • SpringMVC调用方法前,会优先调用方法上标注了@ModelAttributes的方法。

      • 将@ModelAttributes中的属性保存到map中,可以在执行表单提交生成对象之前,替换执行方法同名的形参。

        @ModelAttribute
        public void before(Map<String, Object> map,User user) {
        	user.setName("123");
        	user.setPass("123456);
        	map.put("userInfo", user);
        }
        
        @RequestMapping(value="/testModelAttribute")
        	public String testModelAttribute(User user) {
        	student.setName("456");
        	System.out.println(user);
        	return "success";
        }
        
          ### 自定义视图	
        
  // 添加一个自定义视图,实现View接口。
  @Component  //把视图放到IOC容器里面 ,这里视图的名字就是helloView
  public class HelloView implements View {

    @Override
    public String getContentType() {
        return "text/html";
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        response.getWriter().println("hello view current time : " + new Date());
    }
  }
  <!-- 通过BeanNameViewResolver定义名称视图解析器。 -->
  <!-- BeanNameViewResolver 解析器:使用视图的名字来解析视图 -->
  <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
    <!-- order值越小优先级越高 -->
    <!-- InternalResourceViewResolver的order值是inter的最大值,所以一般来说都是最后调用的 -->
    <property name="order" value="100" />
  </bean>
  <!-- 在Spring 配置文件中将自定义视图的包添加到自动扫描路径中。 -->
  <context:component-scan base-package="com.znsd.springmvc.view" />
@RequestMapping(value="/testCustomView",method=RequestMethod.GET)
public ModelAndView testCustomView() {
	return new ModelAndView(new HelloView());
}
6. 关于重定向与转发
  • 一般情况下,控制器返回字符串类型的值会被当成逻辑视图名进行处理。

  • 如果返回字符串中带有forward:或者redirect:前缀时,SpringMVC会将其进行特殊处理。将forward:和redirect:作为指示符,其后面字符串作为url来处理。

      // 当使用转发与重定向时 springmvc不会使用视图解析配置前后缀不会添加,转发可以访问WEB-INF下文件,重定向不能
      @RequestMapping("forward")
      public String testForward() {
          return "forward:/success.jsp"; // 会完成一个到 success.jsp的转发操作。
      }
    
      @RequestMapping("redirect")
      public String testRedirect() {
          return "redirect:/success.jsp"; // 会完成一个到 success.jsp的重定向操作。
      }
    
7. REST的描述
  • 用URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作
  • REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口)
  • Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。例如:web_service/studentInfo----获取学生信息
  • 用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转
    • GET 获取资源/POST 新建资源/PUT 更新资源/DELETE 删除资源
  • Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。当然还可以压缩HTTP传输时的数据
  • 用 HTTP Status Code传递Server的状态信息。比如最常用的 200 表示成功,500 表示Server内部错误等
8. REST的限制与优点
  • 客户-服务器(Client-Server)客户端服务器分离 ,
    • 提高用户界面的便携性(操作简单)
    • 通过简化服务器提高可伸缩性(高性能,低成本)
    • 允许组件分别优化(可以让服务端和客户端分别进行改进和优化)
  • 无状态(Stateless):客户端的每个请求要包含服务器所需要的所有信息
    • 提高可见性(可以单独考虑每个请求)
    • 提高了可靠性(更容易从局部故障中修复)
    • 提高可扩展性(降低了服务器资源使用)
  • 缓存(Cachable)
    • 减少交互次数,交互的平均延迟
  • 分层系统(Layered System)
    • 系统组件不需要知道与他交流组件之外的事情。封装服务,引入中间层,限制了系统的复杂性,提高可扩展性
  • 统一接口(Uniform Interface)
    • 提高交互的可见性,鼓励单独改善组件
  • 支持按需代码(Code-On-Demand 可选)
    • 提高可扩展性
9. HTTP请求的四种状态
  • GET:获取资源
  • POST:新建资源
  • PUT:更新资源
  • DELETE:删除资源
10. 数据转换器
  1. 自定义数据转换器

    @Component
    public class MyConverter implements Converter<String, User> {
    
    	@Override
    	public Student convert(String source) {//前台传过来一串字符串,通过split分割成一个String数组
    		String [] str = source.split("-");
    		User user = new User();
    		user.setName(str[0]);
    		user.setPass(str[1]);
    		return user;
    	}
    
    }
    
  2. 将自定义的数据转换器放入SpringMvc提供的转换器中

    <!-- FormattingConversionServiceFactoryBean 包含了 ConversionServiceFactoryBean ,既可以数据转换也可以数据格式化 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    		<property name="converters">
    			<set>
    				<ref bean="myConverter" />
    			</set>
    		</property>
    </bean>
    
  3. 将转换器注册到annotation-driven中

    <!-- 该配置为springmvc基础配置,很多功能需要该注解来协调,建议配置文件配完后加入该注解 -->
    <mvc:annotation-driven conversion-service="conversionService" />
    
  4. 创建jsp

    <a href="handler/testConverter.action?studentInfo=3-第十三-?">testConverter</a>
    
  5. 创建测试方法
    @RequestMapping(value="/testConverter",method=RequestMethod.GET)
    public ModelAndView testConverter(@RequestParam("studentInfo") Student student) {
    	System.out.println(student);
    	return new ModelAndView("success");
    }
    
11. 数据校验

​ 注意:springMvc是没有校验的,它使用的校验是Hibernate框架的

  1. 导入依赖

    <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
    	<dependency>
    		<groupId>org.hibernate.validator</groupId>
    		<artifactId>hibernate-validator</artifactId>
    		<version>6.0.13.Final</version>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
    	<dependency>
    		<groupId>javax.validation</groupId>
    		<artifactId>validation-api</artifactId>
    		<version>2.0.1.Final</version>
    	</dependency>
    	<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
    	<dependency>
    		<groupId>org.jboss.logging</groupId>
    		<artifactId>jboss-logging</artifactId>
    		<version>3.3.2.Final</version>
    	</dependency>
      </dependencies>
    
    1. 在相应字段添加校验注解
    @Email
    private String email;
    
    注解说明
    @Null必须为null
    @NotNull必须不为null
    @AssertTrue必须为true
    @AssertFalse必须为false
    @Min(value)必须为一个数字,其值必须大于等于指定的最小值
    @Max(value)必须为一个数字,其值必须小于等于指定的最小值
    @DecimalMin(value)必须为一个数字,其值必须大于等于指定的最小值
    @DecimalMax(value)必须为一个数字,其值必须小于等于指定的最小值
    @Size(max,min)元素的大小必须在指定范围内
    @Digits(int,fraction)必须是一个数字,其值必须在可接受范围内
    @Past必须是一个过去的日期
    @Future必须是一个将来的日期
    @Pattern(value)其值必须符合指定的正则表达式
    hibernate Validator扩展注解
    • Hibernate Validator是JSR3.0的一个扩展组件,除支持所有标准的效验注解外,它还支持以下扩展注解
    注解说明
    @Email被修饰的元素必须是电子邮件
    @Length被修饰的元素长度必须在指定的范围内
    @NotEmpty被修饰的元素必须非空
    @Range被修饰的元素必须在合适的范围内
    1. 编写测试方法
    @RequestMapping(value="/testFormat",method=RequestMethod.POST)
    public String testFormat(@Valid User user, BindingResult result,Map<String, Object> map) {
        if (result.getErrorCount() > 0) {
            for (FieldError error : result.getFieldErrors()) {
                System.out.println("------>"+error.getDefaultMessage());
                map.put("errors", result.getFieldErrors());
            }
        }
        return "login";
    }
    
12. 基于Accept-Language实现国际化
  1. 编写properties

    i18n_zh_CN.properties

    resource.name=\u5148\u751F
    resource.msg=\u4F60\u597D
    

    i18n_en_US.properties

    resource.name=先生
    resource.msg=你好
    
    1. 配置bean
    <!-- 国际化 springmvc会自动扫描id为messageSource的bean 然后把该bean的配置介入 -->
    	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    		<property name="basename" value="i18n" />
    	</bean>
    
    1. 创建视图并且导入<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt”%>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
    <%
    	String path = request.getContextPath();
    	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Test</title>
    </head>
    <body>
    	<fmt:message key="resource.describe" />
    	<fmt:message key="resource.oneself" /> 
    </body>
    </html>
    

    是跟据当前地区转换页面可以设置浏览器语言查看出效果

13. 基于HttpSession实现国际化(多种手动语言切换)
  1. 编写properties

    i18n_zh_CN.properties

    resource.name=\u5148\u751F
    resource.msg=\u4F60\u597D
    

    i18n_en_US.properties

    resource.name=先生
    resource.msg=你好
    
    1. 配置bean
    <!-- 国际化 springmvc会自动扫描id为messageSource的bean 然后把该bean的配置介入 -->
    	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    		<property name="basename" value="i18n" />
    	</bean>
    <!-- 自定义国际化 -->
    	<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" >
    		<property name="defaultLocale" value="zh_CN" />	<!-- 默认为中文 -->
    	</bean> 
        <mvc:interceptors>
          <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /> <!-- 需放在拦截器中 -->
        </mvc:interceptors>
    
    1. 创建视图并且导入<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt”%>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
    <%
    	String path = request.getContextPath();
    	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Test</title>
    </head>
    <body>
    	<fmt:message key="resource.describe" />
    	<fmt:message key="resource.oneself" /> 
    </body>
    </html>
    
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%
    	String path = request.getContextPath();
    	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    	
    	<!-- start 使用message 标签配置需要显示的国际化文本,  locale  对应国际化文件中对应的键的名称  -->
        <a href="hello.action?locale=zh_CN">Chinese</a>
    	<a href="hello.action?locale=en_US">English</a>
    </body>
    </html>
    
14. 拦截器
  1. bean实现拦截器

    package com.znsd.springmvc.expand;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    public class MyInterceptor implements HandlerInterceptor {
    
      /**
         * 进入目标方法之前调用
         * 返回true:则继续调用后续的拦截器和目标方法
         * 返回false:则不会调用后续的拦截器和目标方法
         * 使用场景:权限控制、日志处理、事务...
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println("FirstInterceptor.preHandle()");
            return true;
        }
    
        /**
         * 调用目标方法之后,在渲染页面之前调用
         * 使用场景:
         * 1.需要改变request对象中的值
         * 2.需要修改modelAndView中的值
         * 3.修改转向的视图
         */
        @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()");
        }
    	
    }
    
    1. 自定义拦截器
    <mvc:interceptors>
          <mvc:interceptor>
          	<mvc:mapping path="/handler/testInterceptor.action"/>
          	<bean class="com.znsd.springmvc.expand.MyInterceptor" />
          </mvc:interceptor>
        </mvc:interceptors>
    
15. 文件的上传与下载
  1. jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
  <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="handler/fileupload.action" method="post" enctype="multipart/form-data">
	    <input type="file" name="file" /> 
	    <input type="submit" value="上传" />
	</form>
</body>
</html>
  1. handler
package com.znsd.springmvc.handler;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

import javax.servlet.ServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/handler")
public class DemoHandler {

	@RequestMapping("/fileupload")
	public String fileupload(ServletRequest request, @RequestParam("file") MultipartFile file, Model model)
	    throws IOException {
	    if (!file.isEmpty()) {
	        String imageurl = saveFile(request, file);
	        model.addAttribute("imageurl", imageurl);
	    } else {
	        model.addAttribute("message", "请选择要上传的文件");
	    }
	    return "success";
	}
    
    // 下载
    @RequestMapping("/downFile")
	  public ResponseEntity<byte[]> testdownFile(HttpSession session) throws IOException {
	      ServletContext servletContext = session.getServletContext();
	      InputStream in = servletContext.getResourceAsStream("downloads/down.txt");
	      byte[] bytes = FileCopyUtils.copyToByteArray(in);

	      HttpHeaders header = new HttpHeaders();
	      header.add("Content-Disposition", "attachment;filename=down.txt");

	      ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(bytes, header, HttpStatus.OK);
	      return entity;
	  }
	
	private String saveFile(ServletRequest request, MultipartFile file) throws IOException {
	    // 获取文件的上传路径
	    String uploadPath = request.getServletContext().getRealPath("uploads");
	    System.out.println(uploadPath);
	    File uploadPathFile = new File(uploadPath);
	    if (!uploadPathFile.exists()) {
	        uploadPathFile.mkdirs();
	    }
	    // 获取文件名称
	    String filename = file.getOriginalFilename();
	    // 截取文件后缀
	    String fileext = filename.substring(filename.lastIndexOf("."));
	    // 生成新的随机文件名称
	    String newfileName = UUID.randomUUID() + fileext;
	    // 文件保存路径
	    File savePath = new File(uploadPath + "/" + newfileName);
	    // 上传文件
	    file.transferTo(savePath);
	    return "uploads/" + newfileName;
	}
}
16. 异常的处理方式
  1. 配置xml

    <!-- 配置使用SimpleMappingExceptionResolver来映射异常 -->
      <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
          <!-- 给异常命名一个别名 -->
          <property name="exceptionAttribute" value="ex"></property>
          <property name="exceptionMappings">
              <props>
                  <!-- 一定要异常的全类名。 表示出现异常,就跳转到error.jsp视图 -->
                  <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
              </props>
          </property>
      </bean>
    
    1. @ExceptionHandler注解实现异常处理异常类
    /**
     * 全局异常处理类,在项目中推荐使用全局异常处理类去处理所有异常信息
     * @author Administrator
     */
    @ControllerAdvice
    public class ExceptionHandlerAdvice {
    
    
        /**
         * 在项目总如果没有对异常有页面要求,那么一个异常页面就够了
         * 有些项目需要对每一类型的异常都有对象异常页面,比如前台的异常处理、后台异常处理
         * @param request
         * @param response
         * @param handler
         * @param ex
         * @return
         */
        @ExceptionHandler(value = { NullPointerException.class, IndexOutOfBoundsException.class })
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                Exception ex) {
            // 如果要将异常传递到视图中(jsp页面),必须使用ModelAndView来进行数据传递
            // 不能使用Map形参的方式,否则会报错
            System.out.println("ExceptionHandlerAdvice.resolveException()");
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("ex", ex);
            ModelAndView mv = new ModelAndView("error", map);
            return mv;
        }
    }
    
    1. HandlerExceptionResolver 接口自定义异常处理器
      @Component // 将自定义异常类装载到spring容器中
      public class CustomeException implements HandlerExceptionResolver {
    
        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                Exception ex) {
            Map<String, Object> map = new HashMap<String, Object>();
            if (ex instanceof NullPointerException) {
                map.put("ex", ex);
                return new ModelAndView("nullPointer", map); // 指定异常对应的视图页面
            } 
            if (ex instanceof IndexOutOfBoundsException) {
                return new ModelAndView("indexOutOf", map); // 指定异常对应的视图页面
            }
            return new ModelAndView("error", map);
        }
      }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值