Spring MVC
SpringMVC
1.1 回顾Servlet
-
新建一个普通的Maven项目,删除src目录
-
在该项目中添加一个普通的maven项目模块
-
添加web框架支持
-
导入项目需要的依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
- 编写前端jsp页面(form表单接收用户输入信息)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--form表单--%>
<form method="post" action="/servlet">
<input type="text" name="method">
<input type="submit">
</form>
</body>
</html>
- 编写Servlet(接收前端数据并转发页面)
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.接收表单提交数据
String method = req.getParameter("method");
//2.处理数据
if (method.equals("post")){
//将post存入session
req.getSession().setAttribute("msg","使用post请求");
}else if (method.equals("get")){
//将get存入session
req.getSession().setAttribute("msg","使用get请求");
}
//3.转发或重定向
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 编写用户提交数据后转发到的页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--取出数据展示即可--%>
${msg}
</body>
</html>
- 在web.xml中注册servlet
<?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">
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.rm.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/servlet</url-pattern>
</servlet-mapping>
</web-app>
- 注意点
如果页面用户不可见,放在WEB-INF下。
如果页面用户可见,放在web目录下



1.2 SpringMVC快速入门
- 新建一个Module,添加web的支持
- 确定导入了SpringMVC的依赖
- 配置web.xml,注册DispatcherServlet
web.xml
<?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">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</context-param>
<!--注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springMVC配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 编写SpringMVC的配置文件,名称:springmvc-servlet.xml :[ servlet name]-servler.xml这里的名称按照官方的要求来的。
springmvc-servlet.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
- 添加处理映射器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
- 添加处理器适配器
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
- 添加视图解析器
<!--添加视图解析器
1.获取ModelAndView的数据
2.解析ModelAndView的视图名字(hello)
3.拼接视图名字,找到对应的视图(/WEB-INF/jsp/hello.jsp)
4.将数据渲染到这个视图上
-->
<bean id="InternalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--添加前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
- 编写我们要操作业务Controller,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView:模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView
mv.addObject("msg","HelloSpringMVC");
//封装要跳转的视图"/WEB-INF/jsp/hello.jsp"
mv.setViewName("hello");
return mv;
}
}
- 将自己的类交给springIOC容器,注册bean
<!--handler -->
<bean id="/hello" class="com.rm.controller.HelloController"/>
- 写jsp页面,展示ModelAndView存放的数据,以及正常的展示页面
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
可能遇到的问题
- 404页面
WEB-INF目录下没有生产lib目录
解决方法:新建一个lib目录,将依赖复制进去

- 505界面
找不到springmvc-servlet.xml文件
解决方法:在xml中配置
如果不特意指定参数名为contextConfigLoction的元素,那么spring的ContextLoderListener监听器就会在/WEB-INF/下去寻找并加载该目录下的名为applicationContext.xml这个文件。So,我们应该在web.xml中添加< context-param>标签并再次指定spring核心文件的位置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
1.2.1 使用注解实现springMVC
- 步骤
- 新建一个web项目
- 导入相关jar包(打包的时候保证有lib文件夹)
- 编写web.xml。注册DispatchServlet(映射到springMVC配置文件)
- 编写springMVC配置文件
- 创建对应的控制类,Controller
- 完善前端和Controller之间的对应
- 调试
- 新建一个项目,项目结构

--编写web.xml 注意要使用4.0版本
<?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">
<!--dispatchServlet-->
<servlet>
<servlet-name>dispatchServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会经过该servlet-->
<servlet-mapping>
<servlet-name>dispatchServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
-- 编写springMVC配置文件 注意要先导入约束
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.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">
<!--自动扫描包。让该包下的所有注解生效,方便IOC统一管理必须先导入约束-->
<context:component-scan base-package="com.rm.controller"/>
<!--让springMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!--支持mvc注解驱动,即添加处理映射器,处理器适配器
在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandLerMapping和一个AnnotationMethodHandLerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
-- 创建对应的控制类
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
//model用来存数据
model.addAttribute("msg","HelloSpringMVCAnnotation");
return "hello";
}
}
-- jsp页面(hello.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
使用SpringMVC必须配置的三大件
处理器映射器
处理器适配器
视图解析器
通常我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,不需要在xml中配置了
1.3 Controller及RestFul风格
1.3.1 控制器Controller
- 控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
- 控制器负责解析用户的请求并将其转换为一个模型。
- 在Spring MVC中一个控制器类可以包含多个方法
- 在Spring MVC中,对于Controller的配置方式有很多种
方式一:通过实现Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
//存放数据
mv.addObject("msg","HelloSpringMVC..........");
//转发数据到页面
mv.setViewName("hello");
return mv;
}
}
说明
- 通过实现Controller接口是较老的方法
- 缺点:一个控制器只能有一个方法,如果需要多个方法则必须新建多个Controller
方式二:使用@Controller注解
- 用于声明该类注册到spring中,是一个控制器(在将IOC的时候,还有另外另个注解@Repository和@Service和@Component)
- 配置xml
<?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">
<!-- 第一步,注册DispatchServlet-->
<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:applicationContext.xml</param-value>
</init-param>
<!--设置启动等级-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--设置所有请求都会经过该Servlet-->
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 配置applicationContext.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.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">
<!--第二步,配置xml文件-->
<!--自动扫描包,开启注解支持-->
<context:component-scan base-package="com.controller"/>
<!--配置处理器映射器及处理器适配器-->
<mvc:annotation-driven/>
<!--过滤静态资源-->
<mvc:default-servlet-handler/>
<!--配置视图解析器-->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 创建java类
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
//第三步,编写java类,实现视图跳转
@RequestMapping("/t1")
public String test1(Model model){
//存放数据
model.addAttribute("msg","<h1>Hello SpringMVC1</h1>");
//跳转视图
return "test1";
}
@RequestMapping("/t2")
public String test2(Model model){
//存放数据
model.addAttribute("msg","Hello SpringMVC2");
//跳转视图
return "test1";
}
}
- 编写jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
被@Controller注解标识的类中的所有方法,如果返回值是String,并且有具体页面可以跳转,都会被视图解析器解析
通过两个不同的请求可以实现跳转到同一个页面
- 可以发现,我们的两个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。
RequestMapping
.@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@Controller
@RequestMapping("/c2")
public class HelloController2 {
@RequestMapping("/t1")//访问该地址需要在url地址栏输入.../c2/t1
public String t1(Model model){
model.addAttribute("msg","/c2/t1");
return "test1";
}
}
1.3.2 RestFul风格
概念
- Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能
- 资源:互联网所有的事物都可以被抽象为资源
- 资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
- 分别对应添加、删除、修改、查询。
传统方式操作资源 通过不同的参数来实现不同的效果!方法单一,post和get.
- http://127.0.0.1/item/queryltem.action?id=1查询,GET
- http://127.0.0.1/item/saveltem.action新增,POST
- http://127.0.0.1/item/updateltem.action更新,POST
- http://127.0.0.1/item/deleteltem.action?id=1删除,GET或POST
使用RESTful操作资源 可以通过不同的请求方式来实现不同的效果!
如下:请求地址一样但是功能可以不同!
- http://127.0.0.1/item/1查询,GET
- http://127.0.0.1/item新增,POST.
- http://127.0.0.1/item更新,PUT
- http://127.0.0.1/item/1删除,DELETE
新建一个RestFulController类
在Spring MVC中可以使用@PathVariable注解,让方法参数的值对应绑定到一个URI模板变量上。
@Controller
public class RestFulController {
//原来的传参:http://localhost/add?a=1&b=2
//RestFul风格:http://localhost/add/1/2
@RequestMapping("/add/{a}/{b}")
public String add(@PathVariable int a,@PathVariable int b, Model model){
int res = a+b;
model.addAttribute("msg","结果为"+res);
return "test1";
}
}
可以实现同一URL,根据请求方式不同,结果也不同
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class RestFulController {
//原来的传参:http://localhost/add?a=1&b=2
//RestFul风格:http://localhost/add/1/2
//@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.DELETE)
//http://localhost/add/1/3 点击表单提交按钮,走的是post请求
@PostMapping("/add/{a}/{b}")//以post方式请求
public String add(@PathVariable int a,@PathVariable int b, Model model){
int res = a+b;
model.addAttribute("msg","结果1为"+res);
return "test1";
}
//http://localhost/add/1/3 在url地址栏直接传参数走的是get请求(可以达到url的复用)
@GetMapping("/add/{a}/{b}")//以get方式请求
public String add2(@PathVariable int a,@PathVariable int b, Model model){
int res = a+b;
model.addAttribute("msg","结果2为"+res);
return "test1";
}
}
- a.jsp(以post方式提交表格数据到/add/)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/add/1/3" method="post">
<input type="submit">
</form>
</body>
</html>
1.4 转发和重定向
1.4.1 有视图解析器
转发
- 直接return的就是到拼接好的转发页面
- return "test";
重定向
@Controller
public class TestController1 {
@RequestMapping("/c1/t1")
public String t1(Model model){
model.addAttribute("msg","/c1/t11");
//重定向
//会跳转到首页http://localhost/index.jsp?msg=%2Fc1%2Ft11
return "redirect:/index.jsp";
}
}
1.4.2 无视图解析器
- 注意,无视图解析器就没有ModelAndView,所以无法使用Model存放数据
@Controller
public class TestController1 {
@RequestMapping("/c1/t1")
public void t1(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("msg","无视图解析器转发");
//转发
request.getRequestDispatcher("/WEB-INF/jsp/test1.jsp").forward(request,response);
//重定向 http://localhost/index.jsp
response.sendRedirect("/index.jsp");
}
}
1.5 SpringMVC数据处理
处理提交数据
- 提交的域名称和处理方法的参数名一致
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/t1")
//http://localhost/user/t1?name=zhangsan
public String t1(String name, Model model){
//接收前端传递的数据
System.out.println("前端输入的数据:"+name);
//将数据传递给前端
model.addAttribute("msg","name="+name);
//转发到前端页面
return "test1";
}
}
- 提交的域名称和处理方法的参数名不一致
- 在参数前加上@RequestParam注解(前端参数名)表示该参数是从前端接收过来的
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/t1")
//http://localhost/user/t1?username=zhangsan
public String t1(@RequestParam("username") String name, Model model){
//接收前端传递的数据
System.out.println("前端输入的数据:"+name);
//将数据传递给前端
model.addAttribute("msg","name="+name);
//转发到前端页面
return "test1";
}
}
- 前端传递的参数是一个对象格式的数据
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/t2")
public String t2(User user,Model model){
//接收前端传递的数据
/*
1.接收前端用户传递的参数,判断参数的名字,如果参数名在方法上,可以直接使用
2.假设传递的是一个对象,如果前端传入的字段和类中的属性一致,则匹配的到,不一样的字段显示为Null
*/
//http://localhost/user/t2?id=1&name=zhangsan&age=5
System.out.println("前端输入的数据:"+user);
//将数据传递给前端
model.addAttribute("msg","user="+user);
//转发到前端页面
return "test1";
}
}
- Model只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
- ModelMap继承了LinkedNap ,除了实现了自身的一些方法,同样的继承 linkedMap 的方法和特性;
- ModelAndview可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
1.5.1 解决乱码问题

- form.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/e/t1" method="post">
name<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>
- EncodingController
@Controller
public class EncodingController {
@PostMapping("/e/t1")
public String t1(@RequestParam("name") String name, Model model){
model.addAttribute("msg",name);
return "test1";
}
}

解决方法
- 使用SpringMVC的过滤器,在web.xml中配置
<?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">
<!--注册DispatchServlet-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.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>
<!--配置编码过滤器-->
<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>
注意
- 过滤器拦截路径要使用/* (会过滤jsp页面)
- 如果使用/ 则不会通过过滤器
1.6 JSON
1.6.1 什么是JSON
- JSON(JavaScript object Notation, JS对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。
- 采用完全独立于编程语言的文本格式来存储和表示数据。
- 简洁和清晰的层次结构使得JSON成为理想的数据交换语言。
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在JavaScript 语言中,一切都是对象。因此,任何JavaScript支持的类型都可以通过JSON来表示,例如字符串、数字、对象、数组等。看看他的要求和语法格式:
- 对象表示为键值对,数据由逗号分隔
- 花括号保存对象
- 方括号保存数组
JSON键值对是用来保存JavaScript对象的一种方式,和JavaScript对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号∶分隔,然后紧接着值:
1.6.2 JSON 和JavaScript对象互转
- 要实现从JSON字符串转换为JavaScript对象,使用JSON.parse()方法:
var obj = soN.parse( ' { "a": "Hello","b": "world"}');
//结果是{ a: 'Hello', b: 'world' }
- 要实现从JavaScript对象转换为JSON字符串,使用JSON.stringify()方法:
var json = SON. stringify({a: 'Hello', b: 'world '});
//结果是'{ " a" : "Hello","b": "world"}'

测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
var user = {
name:"张三",
age:12
};
//将对象转换为JSON格式
var json =JSON.stringify(user);
console.log(json);
//将JSON格式转换为JavaScript数据格式
var user =JSON.parse(json);
console.log(user);
</script>
</head>
<body>
</body>
</html>
1.6.3 Jackson
Controller返回JSON数据
在Maven项目中导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.0</version>
</dependency>
- web.xml
<?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">
<!--注册dispatchServlet-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--添加过滤器-->
<filter>
<filter-name>EncodingFilter</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>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- springMVC.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.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">
<!--自动扫描包。让该包下的所有注解生效,方便IOC统一管理必须先导入约束-->
<context:component-scan base-package="com.rm.controller"/>
<!--让springMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!--视图解析器-->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- User实体类(导入lombok依赖)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
不用jackson,直接返回一个对象
@Controller
public class JSController {
@RequestMapping("/a1")
@ResponseBody //加上该注解,这个方法就不会走视图解析器,会直接返回一个字符串
public String json1(){
User user = new User(1, "张三", "qwertasdfg");
System.out.println(user);
return user.toString();
}
}
- 在浏览器上显示结果

使用ObjectMapper
@Controller
public class JSController {
@RequestMapping("/a1")
@ResponseBody
public String json1() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User(1, "张三", "qwertasdfg");
String s = mapper.writeValueAsString(user);
return s;
}
}
- 浏览器显示

- 发现出现了乱码问题,需要设置编码格式为utf-8,以及返回数据类型
- 通过@RequestMapping中的produces属性来解决
@RequestMapping(value = "/a1",produces = "application/json;charset=utf-8")
- 再次测试,问题解决

代码优化
乱码统一解决
- 上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!
- 我们可以在springmvc的配置文件上添加一段消息StringHttpMessageConverter转换配置!
<!--解决json数据转换乱码问题-->
<mvc:annotation-driven>
<mvc:message-converters>
<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>
@RestController
- 该注解作用在类上,表示该类中的所有方法都不会走视图解析器,都会返回一个字符串。
- 前后端分离的话需要返回JSON格式的数据用该注解
@RestController
public class JSController {
@RequestMapping("/a1")
public String json1() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User(1, "张三", "qwertasdfg");
String s = mapper.writeValueAsString(user);
return s;
}
}
将集合数据转换为Json数据输出
@RequestMapping("/a2")
public String json2() throws JsonProcessingException {
List<User> list = new ArrayList<User>();
User user1 = new User(1, "张三", "qwertasdfg");
User user2 = new User(2, "张四", "qwertasdfg");
User user3 = new User(3, "张五", "qwertasdfg");
User user4= new User(4, "张六", "qwertasdfg");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
return new ObjectMapper().writeValueAsString(list);
}

[{"id":1,"name":"张三","password":"qwertasdfg"},
{"id":2,"name":"张四","password":"qwertasdfg"},
{"id":3,"name":"张五","password":"qwertasdfg"},
{"id":4,"name":"张六","password":"qwertasdfg"}]
将Date数据展示到页面上
@RequestMapping("/a3")
public String json3() throws JsonProcessingException {
Date date = new Date();
//hh代表12小时制
//HH代表24小时制
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String s = dateFormat.format(date);
return new ObjectMapper().writeValueAsString(s);
}

不使用时间戳的方式
- 不使用SimpleDateFormat类
- 使用ObjectMapper类完成
@RequestMapping("/a4")
public String json4() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS,false);
//自定义日期格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(simpleDateFormat);
Date date = new Date();
return mapper.writeValueAsString(date);
}
提取为一个工具类
- JSutil .java
public class JSutil {
public static String getJson(Object object,String dateFormat){
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS,false);
//自定义日期格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(simpleDateFormat);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
- 使用
@RequestMapping("/a4")
public String json4() {
Date date = new Date();
return JSutil.getJson(date,"yyyy-MM-dd HH:mm:ss");
}
需求:用户输入一个参数,也有默认的时间格式
- 方法重写
public class JSutil {
public static String getJson(Object object,String dateFormat){
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS,false);
//自定义日期格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(simpleDateFormat);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
//如果用户不输入日期格式,则有默认的
public static String getJson(Object object){
return JSutil.getJson(object,"yyyy-MM-dd HH:mm:ss");
}
}
- 测试
@RequestMapping("/a4")
public String json4() {
Date date = new Date();
return JSutil.getJson(date);
}
1.6.4 FastJson
- fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
fastjson三个主要的类:
【JSONObject代表json对象】
- JSONobject实现了Map接口,猜想JSONObject底层操作是由Map实现的。
- JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
【JSONArray 代表json对象数组】
- 内部是有List接口中的方法来完成操作的。
【JSON代表JSONObject和JSONArray的转化】
- JSON类源码分析与使用
- 仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。
system.out.println("*******Java对象转JSON字符串*******");
string str1 = JSON.toJSONString(userList) ;
system.out.println( "JSON.toJSONString(list)==>"+str1);
string str2 = JSON.toSONString(user1);
system.out.print1n( "JSON.toJSONString(user1)==>"+str2);
system.out.println("******JSON字符串转Java对象*******");
User jp_user1=JSON.parseobject(str2,User.class);
system.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
system.out.println( "******Java对象转JSON对象******");
JSONObject jsonobject1 = (JSONObject)JSON.toJSON(user2);
System.out.println("(JSONObject)JSON.toJSON(user2)==>"+json0bject1.getString( key. "name"));
system.out.println("******JSON对象转Java对象******");
User to_java_user = JSON.toJava0bject(jsonobject1,User.class);
system.out.println("JSON.toJavaObject(json0bject1,User.class)=z>"+to_java_usen);
1.7 拦截器概述
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
- 过滤器
- servlet规范中的一部分,任何java web工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
- 拦截器
- 拦截器是Spring MVC框架自己的,只有使用了SpringMVC框架的工程才能使用
- 拦截器只会拦截访问的控制器方法,如果访问的是jsp/html/css/image/js是不会进行拦截的
1.7.1 自定义拦截器
- 要想自定义实现拦截器,需要实现HandlerInterceptor接口
- 新建一个Model,添加web框架
- 配置web.xml和applicationContext.xml
- 测试环境配置是否成功
- 编写一个拦截器
MyInterceptor
public class MyInterceptor implements HandlerInterceptor {
//return true :放行,执行下一个拦截器
//return false :不执行下一个拦截器
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("=========处理前========");
return true;
}
//这两个方法没有返回值,通常用来添加日志功能
public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("=========处理后========");
}
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("=========清理========");
}
}
TestController
@Controller
public class TestController {
@ResponseBody
@RequestMapping("/t1")
public String t1(){
System.out.println("拦截器执行了。。。。");
return "Hello";
}
}
- 当用户在浏览器输入该访问地址时,会先走拦截器preHandle方法

- 方法执行顺序

- 如果preHandle方法返回值是false,则只执行该方法,不会继续执行Controller中的方法
1.7.2 拦截器实现登录判断验证
- 需求
- 用户不登录的情况不能访问主页
- 需要用到session存放用户的数据,用户点击注销即删除session中的信息
用户登录存放session
@RequestMapping("/login")
public String login(String userName, String password, Model model,
HttpServletRequest request){
//获取session
HttpSession session = request.getSession();
User user = userService.login(userName, password);
model.addAttribute("user",user);
if (user !=null){
//证明登录成功,将数据存入session
session.setAttribute("user",user);
return "redirect:/book/all";
}
return "error";
}
拦截器查看是否存在user的session
- 如果存在,放行
- 如果不存在,不放行,重定向到登录页
package com.rm.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
//配置拦截器
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//获取session
HttpSession session = request.getSession();
if (session.getAttribute("user")!=null){
return true;
}else{
//重定向到登录页面
response.sendRedirect("/index.jsp");
return false;
}
}
}
配置拦截器
- /book下的所有请求都会被拦截器拦截
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/book/**"/>
<bean class="com.rm.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
添加注销功能
- 用户点击注销按钮会移除session中的user
- 移除后再输入/book/all会重定向到登录页
前端
<a class="btn btn-primary"
href="${pageContext.request.contextPath}/book/remove">注销用户</a>
后端
//添加注销功能,用户点击注销即移除session,跳转登录页
@RequestMapping("/book/remove")
public String remove(HttpServletRequest request){
HttpSession session = request.getSession();
session.removeAttribute("user");
return "redirect:/index.jsp";
}

服务器重启会移除所有session
1.8 文件上传和下载
准备工作
-
文件上传是项目开发中最常见的功能之一,springMVC可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
-
前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单中的enctype属性做个详细的说明:
- application/x-www=form-urlencoded:默认方式,只处理表单域中的value属性值,采用这种编码方式的表单会将表单域中的值处理成URL编码方式。
- multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
- text/plain:除了把空格转换为“+”号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache SoftwarFoundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
- Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。·而Spring MVC则提供了更简单的封装。
- Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
- Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache
Commons FileUpload的组件。
- 导包
commons-fileupload
servlet-api必须用高版本的
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
- 配置bean: multipartResolver
【注意!!!这个bean的id必须为: multipartResolver,否则上传文件会报400的错误!在这里栽过坑,教训!】
web.xml
<!--文件上传配置-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--请求的编码格式,必须和jSP的pageEncoding属性一致,
以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M)-->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
前端
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" method="post"
enctype="multipart/form-data">
<input name="file" type="file">
<input type="submit" value="upload">
</form>
</body>
</html>
FileController
@RestController
//文件上传是一个动作,不需要返回一个页面
public class FileController {
//@RequestParam("file")将name=file控件得到的文件封装成
//CommonsMultipartFile 对象,批量上传CommonsMuLtipartFiLe则为数组即可
@RequestMapping( "/upload")
public String fileupload(@RequestParam("file") CommonsMultipartFile file ,
HttpServletRequest request) throws IOException {
//获取文件名:file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName) ){
return "redirect: /index.jsp" ;
}
System.out.println("上传文件名: "+uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if ( ! realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
//文件输入流
InputStream is = file.getInputStream();
//文件输出流
FileOutputStream os = new FileOutputStream(new File(realPath, uploadFileName));
//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ( ( len=is.read(buffer) )!=-1){
os.write( buffer,0,len);
os.flush();
}
os.close();
is.close();
//重定向到首页
return "redirect:/index.jsp";
}
/**采用file.Transto来保存上传的文件
*/
@RequestMapping( "/upload2")
public String fileupload2(@RequestParam("file")CommonsMultipartFile file,
HttpServletRequest request) throws IOException{
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload" );
File realPath = new File(path);
if ( !realPath.exists()) {
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址:"+realPath);
//通过过CommonsMultipartFiLe的方法直接写文件(注意这个时候)
file.transferTo(new File( realPath +"/"+ file.getOriginalFilename()));
return "redirect: /index.jsp";
}
}
下载文件
@RequestMapping("/download")
public String downloads(HttpServletResponse response,
HttpServletRequest request) throws Exception {
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "数据结构与算法.jpg";
//1,设置response 响应头
response.reset();//设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8");//字符编码
response.setContentType("multipart/form-data");//二进制传输数据/设置啊应头
response.setHeader("content-Disposition", "attachment;fileName=" +
URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path, fileName);
//2、读取文件--输入流
InputStream input = new FileInputStream(file);
//3、写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff = new byte[1024];
int index = 0;
//4、执行写出操作
while ((index = input.read(buff)) != -1) {
out.write(buff, 0, index);
out.flush();
out.close();
input.close();
}
return null;
}


浙公网安备 33010602011771号