SpringMVC总结和初识JSON

初识JSON

概念:json是一种类似于xml的文件,但是它比xml更小,传输更快,更容易被解析,而且json在JavaScript中可以直接转化为js对象。非常适合前端去读取到我们后端传递过来的数据。

  • JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
  • JSON 是轻量级的文本数据交换格式
  • JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
  • JSON 具有自我描述性,更易理解

基本语法格式

  • 数据在名称/值对中
  • 数据由逗号分隔
  • 大括号 {} 保存对象
  • 中括号 [] 保存数组,数组可以包含多个对象
  1. 当然json可以存放数字:{“number”:6} ; 字符串{“string”:“小明”};布尔值{“boolean”:true};空值{“flag”:null}。
  2. 数组的形式进行存放var a = [{"name":"jack","age":12},{"name":"bob","age":12}]其中如果要获取bob值写法为a[1].name

常用方法

JSON.parse()

  • JSON 通常用于与服务端交换数据。
  • 在接收服务器数据时一般是字符串。
  • 我们可以使用 JSON.parse() 方法将数据转换为 JavaScript 对象。

语法

  • JSON.parse(text[, reviver])

参数说明:

  • text:必需, 一个有效的 JSON 字符串。
  • reviver: 可选,一个转换结果的函数, 将为对象的每个成员调用此函数。

JSON.stringify()

  • JSON 通常用于与服务端交换数据。
  • 在向服务器发送数据时一般是字符串。
  • 我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串。

语法

  • JSON.stringify(value[, replacer[, space]])

参数说明:

  • value: 必需, 要转换的 JavaScript 值(通常为对象或数组)。
  • replacer: 可选。用于转换结果的函数或数组。
    如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。使用返回值而不是原始值。如果此函数返回 undefined,则排除成员。根对象的键是一个空字符串:""。
    如果 replacer 是一个数组,则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。当 value 参数也为数组时,将忽略 replacer 数组。
  • space:
    可选,文本添加缩进、空格和换行符,如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格,如果 space 大于 10,则文本缩进 10 个空格。space 也可以使用非数字,如:\t。

Java解析JSON

我们和服务器交互一般用得较多的数据传递方式都是 Json 字符串的形式, 保存对象,我们也可以写成一个 Json 字符串然后存储!解析 Json 可以用的是 Gson,Fastjson,jackson

Jackson

导入依赖:

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

快速入门:

@org.junit.Test
    public void testJackson() throws JsonProcessingException {
        //处理集合
        Map<String,Object> map = new HashMap<>();
        map.put("name","jack");
        map.put("age",18);
        ObjectMapper mapper = new ObjectMapper();
        String s = mapper.writeValueAsString(map);
        System.out.println(s);//{"name":"jack","age":18}
        
        //处理对象
        Person person = new Person("爱丽丝","女",18);
        System.out.println(mapper.writeValueAsString(person));//{"name":"爱丽丝","sex":"女","age":18}
        
        //处理List集合
        Person person1 = new Person("爱丽丝","女",19);
        List<Person> list = new ArrayList<>();
        list.add(person);
        list.add(person1);
        System.out.println(mapper.writeValueAsString(list));//[{"name":"爱丽丝","sex":"女","age":18},{"name":"爱丽丝","sex":"女","age":19}]
        
        //可以通过readValue方法进行后端json的解析
        List list1 = mapper.readValue(mapper.writeValueAsString(list), List.class);
        System.out.println(list1);
        //[{name=爱丽丝, sex=女, age=18}, {name=爱丽丝, sex=女, age=19}]
        
        //通过readTree()方法进行数据的读取
        JsonNode jsonNode = mapper.readTree(s);
        JsonNode name = jsonNode.get("name");
        System.out.println(name.asText());//按照String类型转化
        //jack
    }

SpringMVC

mvc

MVC 设计模式一般指 MVC 框架,M(Model)指数据模型层,V(View)指视图层,C(Controller)指控制层。使用 MVC 的目的是将 M 和 V 的实现代码分离,使同一个程序可以有不同的表现形式。其中,View 的定义比较清晰,就是用户界面。

  • 视图层(View):负责**格式化数据并把它们呈现给用户,**包括数据展示、用户交互、数据验证、界面设计等功能。
  • 控制层(Controller):负责接收并转发请求,对请求进行处理后,指定视图并将响应结果发送给客户端。
  • 数据模型层(Model):模型对象拥有最多的处理任务,是应用程序的主体部分,它负责数据逻辑(业务规则)的处理和实现数据操作(即在数据库中存取数据)
    在这里插入图片描述

初识springmvc

Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架本质上相当于 Servlet
在 Spring MVC 框架中,Controller 替换 Servlet 来担负控制器的职责,用于接收请求,调用相应的 Model 进行处理,处理器完成业务处理后返回处理结果。Controller 调用相应的 View 并对处理结果进行视图渲染,最终客户端得到响应信息。

快速入门

  1. 环境搭建:web项目支持,以及相关jar包
		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
        </dependency>
  1. 欢迎界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
 <a target="_self" href="testController">testController</a>
  </body>
</html>
  1. web.xml配置Spring的DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <display-name>Archetype Created Web Application</display-name>
      <!--配置spring的DispatcherServlet用于转发请求与发送视图-->
     <servlet>
       <servlet-name>springmvc</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!--设置参数 绑定spring的配置文件-->
       <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:springmvc-servlet.xml</param-value>
       </init-param>
       <!--设置加载时间为容器开启立即加载-->
       <load-on-startup>1</load-on-startup>
     </servlet>
      <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
      <!--Spring解决中文乱码过滤器的问题-->
        <filter>
            <filter-name>encoding</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>encoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
</web-app>
  1. 编写控制转化类,这里采用实现接口
package cn.supperbro.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class TestController implements Controller {
    @Override
    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView view = new ModelAndView();
        view.addObject("msg","第一个mvc程序");
        view.setViewName("hello");
        return view;
    }
}
  1. 配置springmvc-servlet的spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">
    <!--配置处理器映射器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!--配置处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    <!--视图解析器  引擎模板-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--转发器注册到IOC容器当中-->
    <bean id="/testController" class="cn.supperbro.controller.TestController"/>
</beans>
  1. 测试界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>welcome</title>
</head>
<body>
${msg}
</body>
</html>

注意点:

  1. idea采用添加web支持方式创建的web项目在路径上要添加依赖的jar包。

执行流程:

在这里插入图片描述

视图解析器

URLBasedViewResolver

UrlBasedViewResolver 是对 ViewResolver 的一种简单实现,主要提供了一种拼接 URL 的方式来解析视图。

UrlBasedViewResolver 通过 prefix 属性指定前缀,suffix 属性指定后缀。当 ModelAndView 对象返回具体的 View 名称时,它会将前缀 prefix 和后缀 suffix 与具体的视图名称拼接,得到一个视图资源文件的具体加载路径,从而加载真正的视图文件并反馈给用户。

使用 UrlBasedViewResolver 除了要配置前缀和后缀属性之外,还需要配置“viewClass”,表示解析成哪种视图。示例代码如下。

<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">                <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
<!--不能省略-->
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>

RegisterController 和 LoginController 控制器类的视图路径仅需提供 register 和 login,视图解析器将会自动添加前缀和后缀,此处解析为 /WEB-INF/jsp/register.jsp 和 /WEB-INF/jsp/login.jsp。

上述 viewClass 值为 InternalResourceViewResolver,它用来展示 JSP 页面。如果需要使用 jstl 标签展示数据,将 viewClass 属性值指定为 JstlView 即可。

另外,存放在 /WEB-INF/ 目录下的内容不能直接通过 request 请求得到,所以为了安全性考虑,通常把 jsp 文件放在 WEB-INF 目录下。

InternalResourceViewResolver

InternalResourceViewResolver 为“内部资源视图解析器”,是日常开发中最常用的视图解析器类型。它是 URLBasedViewResolver 的子类,拥有 URLBasedViewResolver 的一切特性。

InternalResourceViewResolver 能自动将返回的视图名称解析为 InternalResourceView 类型的对象。InternalResourceView 会把 Controller 处理器方法返回的模型属性都存放到对应的 request 属性中,然后通过 RequestDispatcher 在服务器端把请求 forword 重定向到目标 URL。也就是说,使用 InternalResourceViewResolver 视图解析时,无需再单独指定 viewClass 属性。示例代码如下。

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
<!--可以省略-->
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>

配置注解开发(推荐)

注解开发,极大程度上减轻了开发负担,不需要再去实现Controller接口了。
重新配置我们的springmvc-servlet.xml(注解开发时添加我们的json)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--自动扫描包,指定该包下的注解生效,有IOC容器统一管理-->
    <context:component-scan base-package="cn.supperbro.controller"/>
    <!--过滤静态资源-->
    <mvc:default-servlet-handler />
    <!--支持mvc注解驱动-->
    <mvc:annotation-driven />
    <!--解决json乱码的问题-->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="UTF-8"/>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                        <property name="failOnEmptyBeans" value="false"/>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    <!--关于映射器和适配器不需要手动配置,采用默认即可-->
    <!--配置处理器映射器
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    配置处理器适配器
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    视图解析器  引擎模板-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  • @Controller注解:
    @Controller 注解用于声明某类的实例是一个控制器。
  • @RequestMapping注解
    一个控制器内有多个处理请求的方法,如 UserController 里通常有增加用户、修改用户信息、删除指定用户、根据条件获取用户列表等。每个方法负责不同的请求操作,而 @RequestMapping 就负责将请求映射到对应的控制器方法上
    在基于注解的控制器类中可以为每个请求编写对应的处理方法。使用 @RequestMapping 注解将请求与处理方法一 一对应即可。
    @RequestMapping 注解可用于类或方法上。用于类上,表示类中的所有响应请求的方法都以该地址作为父路径。
@Controller
public class TestController {
    //@RequestMapping,参数为访问路劲名
    @RequestMapping("/requestMapping")
    public String testRequestMapping(Model model){
        model.addAttribute("msg","model可以进行数据传递");
        return "hello";//返回值hello,会由视图解析器进行字符拼接WEB-INF/jsp/hello.jsp
    }

    @ResponseBody()
    @RequestMapping("/responseBody")
    public String testResponseBody(){
        return "ResponseBody不会进行字符串拼接,会将该字符串字节返回";
    }
}

RestFul风格

Spring REST 风格可以简单理解为:使用 URL 表示资源时,每个资源都用一个独一无二的 URL 来表示,并使用 HTTP 方法表示操作,即准确描述服务器对资源的处理动作(GET、POST、PUT、DELETE),实现资源的增删改查。

  • 例如:/userview.html?id=12 VS /user/view/12
    我们发现 REST 风格的 URL 中最明显的就是参数不再使用“?”传递。这种风格的 URL 可读性更好,使得项目架构清晰,最关键的是 Spring MVC 也提供对这种风格的支持。

案例:
jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
 <a target="_self" href="restful/45/98">restful</a>
  </body>
</html>

控制器

  @RequestMapping("/restful/{num1}/{num2}")
    public String testRestful(@PathVariable int num1,@PathVariable int num2, Model model){
        model.addAttribute("msg",num1+"+"+num2+"="+(num1+num2));
        return "hello";//返回值hello,会由视图解析器进行字符拼接WEB-INF/jsp/hello.jsp
    }

注意:restful是一种风格,或者是一种习惯,其中@PathVariable注解定位参数名

SpringMVC实现页面跳转的方式

方式一:通过视图解析器,通过拼接字符串实现跳转,跳转的方式时用forward;重定向需要加上关键词redirect:字符串
转发:
客户浏览器发送 http 请求,Web 服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发动作,将目标资源发送给客户;在这里转发的路径必须是同一个 Web 容器下的 URL,其不能转向到其他的 Web 路径上,中间传递的是自己的容器内的 request。
重定向:
客户浏览器发送 http 请求,Web 服务器接受后发送 302 状态码响应及对应新的 location 给客户浏览器,客户浏览器发现是 302 响应,则自动再发送一个新的 http 请求,请求 URL 是新的 location 地址,服务器根据此请求寻找资源并发送给客户。
示例:

@Controller
@RequestMapping("/index")
public class IndexController {
    @RequestMapping("/login")
    public String login() {
        //转发到一个请求方法(同一个控制器类可以省略/index/)
        return "forward:/index/isLogin";
    }
    @RequestMapping("/isLogin")
    public String isLogin() {
        //重定向到一个请求方法
        return "redirect:/index/isRegister";
    }
    @RequestMapping("/isRegister")
    public String isRegister() {
        //转发到一个视图
        return "register";
    }
}

方式二:通过HttpServletRequest , HttpServletResponse 的servlet的方式进行跳转
示例:

@RequestMapping("/request")
    public void testServletRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setAttribute("test","request");//获取不到该数据
        request.getRequestDispatcher("requestMapping").forward(request,response);
    }
    @RequestMapping("/response")
    public void testServletResponse(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.sendRedirect("index.jsp");
    }

SpringMVC接收前端参数的方法

  1. 通过实体类bean接收参数
  2. 通过方法的形式参数来接收参数
  3. 通过httpServletRequest来接收参数
  4. 通过@PathVariable接收URL中的请求参数(restful风格)
  5. 通过@RequestParam接收请求参数
    在方法入参处使用 @RequestParam 注解指定其对应的请求参数。@RequestParam 有以下三个参数:
    value:参数名
    required:是否必须,默认为 true,表示请求中必须包含对应的参数名,若不存在将抛出异常
    defaultValue:参数默认值
  6. 通过@ModelAttribute接收请求参数
    @ModelAttribute 注解用于将多个请求参数封装到一个实体对象中,从而简化数据绑定流程,而且自动暴露为模型数据,在视图页面展示时使用。

示例:
准备bean
数据展示页面
控制器

  //通过实体类,bean的属性名和前端参数属性名一致
    ObjectMapper mapper = new ObjectMapper();
    @RequestMapping("/method1")
    public String method1(Person person,Model model) throws JsonProcessingException {
        String s = mapper.writeValueAsString(person);
        model.addAttribute("msg",s);
        return "hello";
    }
    //方法参数 参数名与前端属性名一致
    @RequestMapping("/method2")
    public String method2(String name,String sex,String age,Model model) throws JsonProcessingException {
        model.addAttribute("msg",name+sex+age);
        return "hello";
    }
    //@RequestParam可以指定value value值和前端参数名一致
    @RequestMapping("/method3")
    public String method3(@RequestParam("name")String username, Model model) throws JsonProcessingException {
        model.addAttribute("msg",username);
        return "hello";
    }
    //servlet的request方式获取
    @RequestMapping("/method4")
    public String method4(HttpServletRequest r,Model model) throws JsonProcessingException {
        Map<String, String[]> map = r.getParameterMap();
        String s = mapper.writeValueAsString(map);
        model.addAttribute("msg",s);
        return "hello";
    }
    //通过@ModelAttribute接收请求参数
    @RequestMapping("/method1")
    public String method5(@ModelAttribute("Person") Person person, Model model) throws JsonProcessingException {
        String s = mapper.writeValueAsString(person);
        model.addAttribute("msg");
        return "hello";
    }

springmvc的拦截器

Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。
在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,主要有以下 2 种方式。

  • 通过实现 HandlerInterceptor 接口或继承 HandlerInterceptor 接口的实现类(例如
    HandlerInterceptorAdapter)来定义;
  • 通过实现 WebRequestInterceptor 接口或继承 WebRequestInterceptor 接口的实现类来定义。

实现 HandlerInterceptor 接口

package cn.supperbro.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class TestInterceptor implements HandlerInterceptor {
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行");
    }
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
    }
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle方法在控制器的处理请求方法调用之前执行");
        return false;
    }
}
  • preHandle( ):该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回
    false 表示中断后续操作。
  • postHandle( ):该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
  • afterCompletion( ):该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。

在spring配置文件中添加拦截器

 <!-- 配置拦截器 -->
    <mvc:interceptors>
        <!-- 配置一个全局拦截器,拦截所有请求 -->
        <bean class="cn.supperbro.controller.TestInterceptor" />
        <mvc:interceptor>
            <!-- 配置拦截器作用的路径 -->
            <mvc:mapping path="/**" />
            <!-- 配置不需要拦截作用的路径 -->
            <mvc:exclude-mapping path="" />
            <!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
            <bean class="" />
        </mvc:interceptor>
        <mvc:interceptor>
            <!-- 配置拦截器作用的路径 -->
            <mvc:mapping path="/gotoTest" />
            <!-- 定义在<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
            <bean class="" />
        </mvc:interceptor>
    </mvc:interceptors>
<mvc:interceptors>:该元素用于配置一组拦截器。
<bean>:该元素是 <mvc:interceptors> 的子元素,用于定义全局拦截器,即拦截所有的请求。
<mvc:interceptor>:该元素用于定义指定路径的拦截器。
<mvc:mapping>:该元素是 <mvc:interceptor> 的子元素,用于配置拦截器作用的路径,该路径在其属性 path 中定义。path 的属性值为/**时,表示拦截所有路径,值为/gotoTest时,表示拦截所有以/gotoTest结尾的路径。如果在请求路径中包含不需要拦截的内容,可以通过 <mvc:exclude-mapping> 子元素进行配置。

SpringMVC文件上传

Spring MVC 框架的文件上传基于 commons-fileupload 组件,并在该组件上做了进一步的封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

MultipartResolver接口

在 Spring MVC 中实现文件上传十分容易,它为文件上传提供了直接支持,即 MultpartiResolver 接口。MultipartResolver 用于处理上传请求,将上传请求包装成可以直接获取文件的数据,从而方便操作。

MultpartiResolver 接口有以下两个实现类:

  • StandardServletMultipartResolver:使用了 Servlet 3.0 标准的上传方式。
  • CommonsMultipartResolver:使用了 Apache 的 commons-fileupload 来完成具体的上传操作。
  • MultpartiResolver 接口具有以下方法。
    byte[] getBytes() 以字节数组的形式返回文件的内容
    String getContentType() 返回文件的内容类型
    InputStream getInputStream() 返回一个InputStream,从中读取文件的内容
    String getName() 返回请求参数的名称
    String getOriginalFillename() 返回客户端提交的原始文件名称
    long getSize() 返回文件的大小,单位为字节
    boolean isEmpty() 判断被上传文件是否为空
    void transferTo(File destination) 将上传文件保存到目标目录下
单文件上传( CommonsMultipartResolver)
  1. 环境准备:文件上传使用 Apache Commons FileUpload 组件,需要导入 commons-io-2.4.jar 和 commons-fileupload-1.2.2.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.2.2</version>
        </dependency>
  1. 编写文件上传界面:负责文件上传表单的编码类型必须是“multipart/form-data”类型。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/fileupload"
      method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="myfile"><br>
    文件描述:<input type="text" name="description"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>
  1. 配置SpringIOC,注册 CommonsMultipartResolver
<!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5000000" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>
  1. 创建 FileDomain 类,在该 POJO 类中声明一个 MultipartFile 类型的属性封装被上传的文件信息,属性名与文件选择页面 filleUpload.jsp 中的 file 类型的表单参数名 myfile 相同
package cn.supperbro.domain;

import org.springframework.web.multipart.MultipartFile;

public class FileDomain {
    private String description;
    private MultipartFile myfile;

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public MultipartFile getMyfile() {
        return myfile;
    }

    public void setMyfile(MultipartFile myfile) {
        this.myfile = myfile;
    }
}
  1. 编写控制器
package cn.supperbro.controller;

import cn.supperbro.domain.FileDomain;
import org.springframework.stereotype.Controller;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class FileUploadController {
    // 得到一个用来记录日志的对象,这样在打印信息时能够标记打印的是哪个类的信息
    private static final Log logger = LogFactory.getLog(FileUploadController.class);
    /**
     * 单文件上传
     */
    @RequestMapping("/fileupload")
    public String oneFileUpload(@ModelAttribute FileDomain fileDomain, HttpServletRequest request) {
        /*
         * 文件上传到服务器的位置“/uploadfiles”,该位置是指 部署项目发布后的路径的userFiles用作根路径.
         */
        String rootPath = request.getServletContext().getRealPath("userFiles");
        //获取文件描述作为新文件夹名
        String realpath = fileDomain.getDescription();
        String fileName = fileDomain.getMyfile().getOriginalFilename();
        File targetFile = new File(rootPath+File.separator+realpath, fileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        // 上传
        try {
            //SpringMVC直接将上传文件写入到指定文件中
            fileDomain.getMyfile().transferTo(targetFile);
            logger.info("成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "show";
    }
}
  1. 上传结果界面
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>文件上传</title>
</head>
<body>
文件描述:${fileDomain.description }
<br>
<!-- fileDomain.getMyFile().getOriginalFilename()-->
文件名称:${fileDomain.myfile.originalFilename }
</body>
</html>

多文件上传

  1. 上传界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>多文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/files"
      method="post" enctype="multipart/form-data">
    选择文件1:<input type="file" name="myfile"><br>
    文件描述1:<input type="text" name="description"><br>
    选择文件2:<input type="file" name="myfile"><br>
    文件描述2:<input type="text" name="description"><br>
    选择文件3:<input type="file" name="myfile"><br>
    文件描述3:<input type="text" name="description"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>
  1. 实体类
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

public class FilesDomain {
    private List<String> description;
    private List<MultipartFile> myfile;
    public List<String> getDescription() {
        return description;
    }
    public void setDescription(List<String> description) {
        this.description = description;
    }
    public List<MultipartFile> getMyfile() {
        return myfile;
    }
    public void setMyfile(List<MultipartFile> myfile) {
        this.myfile = myfile;
    }
}
  1. controller
package cn.supperbro.controller;

import cn.supperbro.domain.FilesDomain;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.List;
@Controller
public class FilesUploadController {
    /**
     * 多文件上传
     */
    @RequestMapping("/files")
    public String multiFileUpload(@ModelAttribute FilesDomain FilesDomain, HttpServletRequest request) {
        String realpath = request.getServletContext().getRealPath("uploadfiles");
        File targetDir = new File(realpath);
        if (!targetDir.exists()) {
            targetDir.mkdirs();
        }
        List<MultipartFile> files = multiFileDomain.getMyfile();
        System.out.println("files"+files);
        for (int i = 0; i < files.size(); i++) {
            MultipartFile file = files.get(i);
            String fileName = file.getOriginalFilename();
            File targetFile = new File(realpath, fileName);
            // 上传
            try {
                file.transferTo(targetFile);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "shows";
    }
}
  1. 展示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>多文件上传显示</title>
</head>
<body>
<table border="1px">
    <tr>
        <td>详情</td>
        <td>文件名</td>
    </tr>
    <!-- 同时取两个数组的元素 -->
    <c:forEach items="${FilesDomain.description}" var="description"
               varStatus="loop">
        <tr>
            <td>${description}</td>
            <td>${FilesDomain.myfile[loop.count-1].originalFilename}</td>
        </tr>
    </c:forEach>
    <!-- fileDomain.getMyfile().getOriginalFilename() -->
</table>
</body>
</html>

文件下载

文件下载有以下两种实现方法:

  1. 通过超链接实现下载:实现简单,但暴露了下载文件的真实位置,并且只能下载 Web 应用程序所在目录下的文件,WEB-INF 目录除外。
  2. 利用程序编码实现下载:增强安全访问控制,可以下载除 Web 应用程序所在目录以外的文件,也可以将文件保存到数据库中。

利用程序编码实现下载需要设置以下两个报头:

  • Web 服务器需要告诉浏览器其所输出内容的类型不是普通文本文件或 HTML 文件,而是一个要保存到本地的下载文件,这需要设置 Content-Type 的值为 application/x-msdownload
  • Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置Content-Disposition 报头。

该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。

设置报头的示例如下:
response.setHeader(“Content-Type”, “application/x-msdownload”);
response.setHeader(“Content-Disposition”, “attachment;filename=”+filename);

程序编码文件下载可分为两个步骤:

  1. 在客户端使用一个文件下载超链接,链接指向后台下载文件的方法以及文件名。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<c:forEach begin="1" step="1" end="5">
<p>测试</p>
</c:forEach>
<table>
    <tr>
        <td>被下载的文件名</td>
    </tr>
    <!--遍历 model中的 files-->
    <c:forEach items="${files}" var="filename">
        <tr>
            <td>
                <a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a>
            </td>
        </tr>
    </c:forEach>
</table>
</body>
</html>

  1. 在控制器类中,提供文件下载方法进行下载。
package cn.supperbro.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class FileDownController {
    // 得到一个用来记录日志的对象,在打印时标记打印的是哪个类的信息
    private static final Log logger = LogFactory
            .getLog(FileDownController.class);
    /**
     * 显示要下载的文件
     */
    @RequestMapping("showDownFiles")
    public String show(HttpServletRequest request, Model model) {
        // 从 workspace\.metadata\.plugins\org.eclipse.wst.server.core\
        // tmp0\wtpwebapps\springMVCDemo11\下载
        String realpath = request.getServletContext()
                .getRealPath("uploadfiles");
        File dir = new File(realpath);
        System.out.println(realpath);
        File files[] = dir.listFiles();
        // 获取该目录下的所有文件名
        ArrayList<String> fileName = new ArrayList<String>();
        for (int i = 0; i < files.length; i++) {
            fileName.add(files[i].getName());
        }
        model.addAttribute("files", fileName);
        return "loaddown";
    }
    /**
     * 执行下载
     */
    @RequestMapping("down")
    public String down(@RequestParam String filename,
                       HttpServletRequest request, HttpServletResponse response) {
        String aFilePath = null; // 要下载的文件路径
        FileInputStream in = null; // 输入流
        ServletOutputStream out = null; // 输出流
        try {
            // 从workspace\.metadata\.plugins\org.eclipse.wst.server.core\
            // tmp0\wtpwebapps下载
            aFilePath = request.getServletContext().getRealPath("uploadfiles");
            // 设置下载文件使用的报头
            response.setHeader("Content-Type", "application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename="
                    + toUTF8String(filename));
            // 读入文件
            in = new FileInputStream(aFilePath + "\\" + filename);
            // 得到响应对象的输出流,用于向客户端输出二进制数据
            out = response.getOutputStream();
            out.flush();
            int aRead = 0;
            byte b[] = new byte[1024];
            while ((aRead = in.read(b)) != -1 & in != null) {
                out.write(b, 0, aRead);
            }
            out.flush();
            in.close();
            out.close();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        logger.info("下载成功");
        return null;
    }
    /**
     * 下载保存时中文文件名的字符编码转换方法
     */
    public String toUTF8String(String str) {
        StringBuffer sb = new StringBuffer();
        int len = str.length();
        for (int i = 0; i < len; i++) {
            // 取出字符中的每个字符
            char c = str.charAt(i);
            // Unicode码值为0~255时,不做处理
            if (c >= 0 && c <= 255) {
                sb.append(c);
            } else { // 转换 UTF-8 编码
                byte b[];
                try {
                    b = Character.toString(c).getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    b = null;
                }
                // 转换为%HH的字符串形式
                for (int j = 0; j < b.length; j++) {
                    int k = b[j];
                    if (k < 0) {
                        k &= 255;
                    }
                    sb.append("%" + Integer.toHexString(k).toUpperCase());
                }
            }
        }
        return sb.toString();
    }
}

拓展服务器图片展示

可以用img标签展示即(图片按照IO流输出)

<img src="push?path=D:/ideaproject/ssm/out/artifacts/springmvc_war_exploded/uploadfiles/1.jpg"/>
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

@Controller
public class ShowPictureController {
    @RequestMapping("push")
    public void show(HttpServletRequest request, HttpServletResponse response){
        // TODO Auto-generated method stub
        String pathName = request.getParameter("path");
        File imgFile = new File(pathName);
        FileInputStream fin = null;
        OutputStream output = null;
        try {
            output = response.getOutputStream();
            fin = new FileInputStream(imgFile);
            byte[] arr = new byte[1024*10];
            int n;
            while((n = fin.read(arr)) != -1) {
                output.write(arr,0,n);
            }
            output.flush();
            System.out.println("图像输出完毕");
        }catch(IOException e) {
            e.printStackTrace();
        }
        try {
            output.close();
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值