别人可以替你开车,但不能替你走路;可以替你做事,但不能替你感受。人生的路要靠自己行走,成功要靠自己去争取。天助自助者,成功者自救。你好,我是梦阳辰,期待与你相遇!
文章目录
- 01.概述
- 02.Spring MVC原理分析
- 03.使用注解开发Spring MVC(重点)
- 04.控制器(Controller)
- 05.RestFul风格
- 06.跳转方式(转发和重定向)
- 07.获取前端请求参数&数据回显
- 08.解决乱码问题
- JSON数据
- Controller返回json数据(Jackson)
- FastJson
- json-lib的用法
01.概述
Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中。正式名称“ Spring Web MVC”来自其源模块(spring-webmvc)的名称,但更通常称为“ Spring MVC”。是基于java实现MVC的轻量级Web框架。
官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html
什么是MVC
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
是将业务逻辑、数据、显示分离的方法来组织代码。
MVC主要作用是降低了视图与业务逻辑间的双向偶合。
MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
为什么要学习SpringMVC呢?
Spring MVC的特点:
1.轻量级,简单易学
2.高效,基于请求响应的MVC框架
3.与Spring兼容性好,无缝结合
4.约定优于配置
5.功能强大:RESTful、数据验证、格式化、本地化、主题等
6.简洁灵活
Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。
DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;
正因为SpringMVC好 , 简单 , 便捷 , 易学 , 天生和Spring无缝集成(使用SpringIoC和Aop) , 使用约定优于配置 . 能够进行简单的junit测试 . 支持Restful风格 .异常处理 , 本地化 , 国际化 , 数据验证 , 类型转换 , 拦截器
中心控制器:
与其他许多Web框架一样,Spring MVC围绕前端控制器模式进行设计Servlet,其中DispatcherServlet,Central提供了用于请求处理的共享算法,而实际工作是由可配置的委托组件执行的。该模型非常灵活,并支持多种工作流程。
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。
Spring MVC框架像许多其他MVC框架一样,以请求为驱动,围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet(它继承自HttpServlet基类)。
02.Spring MVC原理分析
SpringMVC的原理如下图所示:
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
Handler让具体的Controller执行。
Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
视图解析器将解析的逻辑视图名传给DispatcherServlet。
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
最终视图呈现给用户。
原理分析案例:
导入依赖:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.2</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>
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">
<!--1.注册DispatcherServlet,请求分发器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
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"/>
<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--Handler-->
<bean id="/mengyangchen" class="com.mengyangchen.controller.FirstController"/>
</beans>
控制层:
package com.mengyangchen.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FirstController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView 模型和视图
ModelAndView modelAndView = new ModelAndView();
//业务
String information ="你好,梦阳辰!";
//封装对象,放在ModelAndView中
modelAndView.addObject("msg",information);
//封装要跳转的视图,放在ModelAndView中
modelAndView.setViewName("mengyangchen"); //: /jsp/mengyangchen.jsp 响应路径
return modelAndView;
}
}
配置本地tomcat
运行,在地址栏输入:
注意:在IDEA的项目发布中,需要添加lib依赖
03.使用注解开发Spring MVC(重点)
导入依赖
按上述步骤配置lib
配置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">
<!--1.注册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>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
配置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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://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.mengyangchen.controller"/>
<!-- 让Spring MVC不处理静态资源 例如 .css .js .html 图片 字体等...-->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<!--默认设置,不需要配置映射器,和处理器了-->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
控制层:
package com.mengyangchen.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller//会被spring接管被这个注解的类,中的所有方法,如果返回值是String,并且有具体页面可以跳转,那么就会被视图解析器解析;
public class FirstController {
/*真实访问地址:项目名/first
* 如果类上面有@RequestMapping("/h1")
* 则真实访问地址为:项目名/h1/first
* 请求路径
* */
@RequestMapping("/first")
public String first(Model model){
//业务层,调用service层得到数据
String msg = "欢迎你,梦阳辰!";
model.addAttribute("msg",msg);
return "first";//交给视图解析器解析地址(相应路径)
}
/*可以配置多个访问路径请求
* 这就大大的减少了大量的servlet
* 简化了开发*/
@RequestMapping("/second")
public String second(Model model){
//业务层,调用service层得到数据
String msg = "欢迎你!";
model.addAttribute("msg",msg);
return "second";//交给视图解析器解析地址(相应路径)
}
}
视图层:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>你好!</title>
</head>
<body>
<p>${msg}</p>
</body>
</html>
目录结构:
EL表答式取出Model中存放的值,或者对象
@Controller是为了让Spring IOC容器初始化时自动扫描到
@RequestMapping是为了映射请求路径
方法中声明Model类型的参数是为了把Action中的数据带到视图中
方法返回的结果是视图的名称,加上配置文件中的前后缀变成真实路径。
注意:如果使用的是@RestController注解,就不会被试图解析器解析(用于json数据)
使用springMVC必须配置的三大件:
处理器映射器、处理器适配器、视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
04.控制器(Controller)
控制器负责提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
控制器负责解析用户的请求并将其转换为一个模型。
在Spring MVC中一个控制器类可以包含多个方法
在Spring MVC中,对于Controller的配置方式有很多种
实现Contorller接口:
//实现该接口的类获得控制器功能
public interface Controller {
//处理请求且返回一个模型与视图对象
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
实现接口Controller定义控制器是较老的办法
缺点:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦。
使用注解@Controller
@Controller注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解)
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描
<!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 -->
<context:component-scan base-package="com.kuang.controller"/>
使用注解实现:
//@Controller注解的类会自动添加到Spring上下文中
@Controller
public class FirstController{
//映射访问路径
@RequestMapping("/test")
public String index(Model model){
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "你好,梦阳辰!");
//返回视图位置
return "first";
}
}
可以发现,我们的多个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。
@RequestMapping
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
05.RestFul风格
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。分别对应 添加、 删除、修改、查询。
使用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
紧接着上面的测试代码进行练习:
使用method属性指定请求类型
用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
Get提交:
@Controller
public class RestFulController {
@RequestMapping(value = "/first/{a}/{b}",method = {RequestMethod.GET})
public String test(@PathVariable int a , @PathVariable int b, Model model){
int msg = a+b;
model.addAttribute("msg",msg);
return "first";
}
}
POST提交:
首页:
<body>
注解开发
<form action="/chapter02_springMVC/first/11/2" method="post">
<input type="submit" value="提交">
</form>
</body>
控制类:
@Controller
public class RestFulController {
@RequestMapping(value = "/first/{a}/{b}",method = {RequestMethod.GET})
public String test(@PathVariable int a , @PathVariable int b, Model model){
int msg = a+b;
model.addAttribute("msg",msg);
return "first";
}
@RequestMapping(value = "/first/{a}/{b}",method = {RequestMethod.POST})
public String test2(@PathVariable int a , @PathVariable int b, Model model){
int msg = a*b;
model.addAttribute("msg",msg);
return "first";
}
}
现在可以看出:虽然地址相同,但是因为提交的方式不同,执行的方法也不同,所以也会有不同的结果。
方法级别的注解变体有如下几个:组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一个组合注解,平时使用的会比较多!
它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式。
例如:
@GetMapping("/first/{a}/{b}")
public String test(@PathVariable int a , @PathVariable int b, Model model){
int msg = a+b;
model.addAttribute("msg",msg);
return "first";
}
使用路径变量的好处?
使路径变得更加简洁;
获得参数更加方便,框架会自动进行类型转换。
通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法。
06.跳转方式(转发和重定向)
前面我们:
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
public class FirstController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","你好,梦阳辰!");
mv.setViewName("first");
return mv;
}
}
用servlet原来的方式,进行跳转。不需要视图图解析器。(不推荐使用)
通过HttpServletRequest实现转发
通过HttpServletResponse实现重定向
@Controller
public class ServletController {
@GetMapping("/first11/{a}/{b}")//请求路径
public void forwardTest(@PathVariable int a, @PathVariable int b , HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int msg = a+b;
//转发
request.setAttribute("msg",msg);
request.getRequestDispatcher("/jsp/first.jsp").forward(request,response);
}
@GetMapping("/first12/{a}/{b}")//请求路径
public void sendRedirectTest(@PathVariable int a, @PathVariable int b , HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int msg = a*b;
HttpSession session = request.getSession();
session.setAttribute("msg",msg);
//重定向
response.sendRedirect("/chapter02_springMVC/jsp/second.jsp");
}
}
转发结果:
重定向结果:
使用SpringMVC来实现转发和重定向:(有视图解析器)
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方。
@Controller
public class SpringMVC_controller {
@GetMapping("/springMVC-have/{a}/{b}")//请求路径
public String test(@PathVariable int a, @PathVariable int b, Model model){
int msg = a +b;
model.addAttribute("msg",msg);
return "first";//转发
}
@GetMapping("/springMVC-have1/{a}/{b}")//请求路径
public String test1(@PathVariable int a, @PathVariable int b, Model model){
int msg = a +b;
model.addAttribute("msg",msg);
return "redirect:/jsp/second.jsp";//重定向
}
}
转发:
重定向:
使用SpringMVC来实现转发和重定向:(没有视图解析器)
1.删除配置的视图解析器
@GetMapping("/springMVC-no/{a}/{b}")//请求路径
public String test2(@PathVariable int a, @PathVariable int b, Model model){
int msg = a +b;
model.addAttribute("msg",msg);
return "/jsp/first.jsp";//转发
}
@GetMapping("/springMVC-no1/{a}/{b}")//请求路径
public String test3(@PathVariable int a, @PathVariable int b, Model model){
int msg = a +b;
model.addAttribute("msg",msg);
return "forward:/jsp/first.jsp";//转发
}
@GetMapping("/springMVC-no2/{a}/{b}")//请求路径
public String test4(@PathVariable int a, @PathVariable int b, Model model){
int msg = a +b;
model.addAttribute("msg",msg);
return "redirect:/jsp/second.jsp";//重定向
}
删除视图解析器,运行结果都没有问题。
但是
如果没有删除视图解析器
第二种转发:
重定向:
总结:用springMVC写重定向路径时,可以不需要项目目录。
07.获取前端请求参数&数据回显
http://localhost/chapter02_springMVC/test?name=mengyangchen 1、提交的域名称和处理方法的参数名一致
@RequestMapping("/test")
public String hello(String name){
System.out.println(name);
return "first";
}
http://localhost/chapter02_springMVC/test1?username=mengyangchen 2、提交的域名称和处理方法的参数名不一致
@RequestMapping("/test1")
public String hello1(@RequestParam("username") String name){
System.out.println(name);
return "first";
}
3、提交的是一个对象
实体类:
public class User {
private int id;
private String name;
private int age;
//构造
//get/set
//tostring()
}
http://localhost/chapter02_springMVC/test2?username=mengyangchen&id=1&age=17
@RequestMapping("/test2")
public String user(User user){
System.out.println(user);
return "first";
}
如果使用对象的话,前端传递的参数名和对象名必须一致,否则就是null。
数据显示到前端
第一种 : 通过ModelAndView
第二种 : 通过Model
第三种 : 通过ModelMap
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性。
08.解决乱码问题
前端是提交的参数是中文数据,出现乱码。
第一种:前端序列化参数乱码。
可以在前端对序列化后的参数进行URL编码处理。
springMVC解决乱码问题:
SpringMVC给我们提供了一个过滤器
在web.xml中配置 :
<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>
通用乱码问题解决方案:
自定义过滤器:
package com.mengyangchen.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
1、修改tomcat配置文件 :设置编码!
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
JSON数据
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON 和 JavaScript 对象互转
要实现从JSON字符串转换为JavaScript 对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//结果是 {a: 'Hello', b: 'World'}
要实现从JavaScript 对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'});
//结果是 '{"a": "Hello", "b": "World"}'
Controller返回json数据(Jackson)
Jackson应该是目前比较好的json解析工具了,当然工具不止这一个,比如还有阿里巴巴的 fastjson ,json-lib等等.
我们这里使用Jackson,使用它需要导入它的jar包;
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</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">
<!--1.注册servlet-->
<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>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--springMVC解决参数乱码问题-->
<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>
配置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
http://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.mengyangchen.controller"/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
实体类:
package com.mengyangchen.pojo;
import java.io.Serializable;
public class User implements Serializable {
private String name;
private int age;
private String sex;
public User() {
}
public User(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
控制层:
@Controller
public class FirstJsonController {
@RequestMapping("/json")
@ResponseBody //不走视图解析器
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("梦阳辰", 20, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
可以看到出现乱码问题:
方法1:
通过@RequestMaping的produces属性来实现,修改下代码
//produces:指定响应体返回类型和编码
@RequestMapping(value = "/json",produces = "application/json;charset=utf-8")
方法2 :
上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!
springmvc的配置文件上添加一段消息StringHttpMessageConverter转换配置
<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>
集合输出
@Controller
public class FirstJsonController {
@RequestMapping("/json")
@ResponseBody //不走视图解析器
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
List<User> list = new LinkedList<>();
//创建一个对象
User user1 = new User("梦阳辰", 20, "男");
User user2 = new User("梦", 20, "男");
User user3 = new User("阳辰", 20, "男");
list.add(user1);
list.add(user2);
list.add(user3);
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(list);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
处理时间数据:
抽取转换为json的代理作为工具类:
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object,"yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object,String dateFormat) {
ObjectMapper mapper = new ObjectMapper();
//不使用时间差的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
//指定日期格式
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
控制层:
@Controller
public class FirstJsonController {
@RequestMapping("/json")
@ResponseBody //不走视图解析器
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
List<User> list = new LinkedList<>();
//创建一个对象
User user1 = new User("梦阳辰", 20, "男",new Date());
User user2 = new User("梦", 20, "男",new Date());
User user3 = new User("阳辰", 20, "男",new Date());
list.add(user1);
list.add(user2);
list.add(user3);
//将我们的对象解析成为json格式
String str = JsonUtils.getJson(list);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
结果:
实体类中包含集合数据:
package com.mengyangchen.pojo;
import java.util.List;
public class State {
private String status;//操作是否成功
private List<User> users;
public State() {
}
public State(String status, List<User> users) {
this.status = status;
this.users = users;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
@Override
public String toString() {
return "State{" +
"status='" + status + '\'' +
", users=" + users +
'}';
}
}
控制层:
package com.mengyangchen.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mengyangchen.pojo.State;
import com.mengyangchen.pojo.User;
import com.mengyangchen.util.JsonUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
@Controller
public class FirstJsonController {
@RequestMapping("/json")
@ResponseBody //不走视图解析器
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
List<User> list = new LinkedList<>();
//创建一个对象
User user1 = new User("梦阳辰", 20, "男",new Date());
User user2 = new User("梦", 20, "男",new Date());
User user3 = new User("阳辰", 20, "男",new Date());
list.add(user1);
list.add(user2);
list.add(user3);
//将我们的对象解析成为json格式
String str = JsonUtils.getJson(list);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
@RequestMapping("/json2")
@ResponseBody //不走视图解析器
public String json2() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
List<User> list = new LinkedList<>();
//创建一个对象
User user1 = new User("梦阳辰", 20, "男",new Date());
User user2 = new User("梦", 20, "男",new Date());
User user3 = new User("阳辰", 20, "男",new Date());
list.add(user1);
list.add(user2);
list.add(user3);
State state = new State();
state.setUsers(list);
state.setStatus("操作成功!");
//将我们的对象解析成为json格式
String str = JsonUtils.getJson(state);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
结果:
不在地址栏访问改为表单提交:
<body>
<form action="/chapter03_springMVC/json" method="get">
<input type="submit" value="提交">
</form>
</body>
总结:
采用这种json数据的格式,后台数据直接返回给当前页面,不会进行页面的跳转。(之前的采用视图解析器的适用于转发和重定向)。
在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!
FastJson
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。
它可以已经将其封装成json工具类了,直接使用即可,它支持对时间数据的支持:
导入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
fastjson 三个主要的类:
JSONObject 代表 json 对象
JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
JSONObject实现了Map接口
内部是有List接口中的方法来完成操作的。
JSON代表 JSONObject和JSONArray的转化
仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化.
@RequestMapping("/json")
@ResponseBody //不走视图解析器
public String json1() throws JsonProcessingException {
List<User> list = new LinkedList<>();
//创建一个对象
User user1 = new User("梦阳辰", 20, "男",new Date());
User user2 = new User("梦", 20, "男",new Date());
User user3 = new User("阳辰", 20, "男",new Date());
list.add(user1);
list.add(user2);
list.add(user3);
System.out.println("*******Java对象 转 JSON字符串(包括时间格式)*******");
String str = JSON.toJSONStringWithDateFormat(list,JSON.DEFFAULT_DATE_FORMAT);
String st = JSON.toJSONStringWithDateFormat(list,"yyyy-MM-dd");
System.out.println("*******Java对象 转 JSON字符串*******");
String str1 = JSON.toJSONString(list);
System.out.println("JSON.toJSONString(list)==>"+str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1)==>"+str2);
System.out.println("\n****** JSON字符串 转 Java对象*******");
User jp_user1=JSON.parseObject(str2,User.class);
System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
System.out.println("\n****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));
System.out.println("\n****** JSON对象 转 Java对象 ******");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
return st;
}
json-lib的用法
导入依赖或jar包
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
There is no elevator to success.You have to take the stairs.