前言:

本文内容:乱码问题解决、什么是JSON、Jackson使用

推荐免费SpringMVC基础教程视频:【狂神说Java】SpringMVC最新教程IDEA版通俗易懂_哔哩哔哩_bilibili

乱码问题解决

提交表单或者页面显示中文容易出现乱码问题

encoding.jsp

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="eco/pt">
<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>

EncodingController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.jokerdig.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

/**
* @author Joker大雄
* @data 2022/6/4 - 16:58
**/
@Controller
public class EncodingController {

@PostMapping("eco/pt")
public String encoding(Model model,String name){
model.addAttribute("msg",name);
return "test";
}
}

运行,输入中文小王提交表单,出现乱码

1
小王

我们发现在后端的时候数据就已经乱码

解决乱码

使用过滤器解决乱码

新建EncodingFilter.java实现Filter,重写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.jokerdig.filter;

import javax.servlet.*;
import java.io.IOException;

/**
* @author Joker大雄
* @data 2022/6/4 - 17:32
**/
public class EncodingFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 解决乱码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");

chain.doFilter(request,response);
}

@Override
public void destroy() {

}
}

web.xml中配置过滤器

1
2
3
4
5
6
7
8
9
<!--    乱码过滤器 /*包括jsp页面 / 则不包括jsp页面-->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.jokerdig.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

运行之前的代码,乱码问题解决

1
小王

直接使用SpringMVC提供的过滤器,解决乱码问题

直接在web.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--    springMVC过滤器-->
<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>

运行测试,乱码解决

1
小王

使用自定义过滤器解决乱码问题

没找到原作者地址,这是一个大佬写的鸭( •̀ ω •́ )✧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* 解决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;
}
}

web.xml配置该过滤器即可

什么是JSON

JSON概述

  • JSON(JavaScript Object Notation,JS对象标记)是一种轻量级的数据交换格式,使用非常广泛
  • 采用完全独立于编程语言的文本格式来存储和表示数据
  • 简洁清晰的层次结构使得JSON称为理想的数据交换语言
  • 方便阅读和编写,同时也方便机器解析和生成,有效提升网络传输效率

在JavaScript语言中,一切都是对象。因此JavaScript支持的类型都可以通过JSON来表示。(字符串,数字,对象,数组等)

  • 对象表示为键值对,数据由逗号分隔
  • 大括号{}保存对象
  • 方括号[]保存数组

JSON键值对是用来保存JavaScript对象的一种方式,和JavaScript对象的写法也大同小异,书写格式:{"键名":"键值"}

1
2
{"name":"小王"}
{"age":"18"}

JSON是JavaScript对象的字符串表示法,它使用文本表示一个JS对象的信息,本质是一个字符串

1
2
var obj = {a:'hello',b:'world'}; // 这是一个js对象,键名也可以使用引号包裹
var json = '{"a":"hello","b":"world"}'; // 这是一个JSON字符串

JSON和JavaScript对象互相转换

  • 要实现从JSON字符串转换为JavaScript对象,使用JSON.parase()方法

    1
    2
    var obj = JSON.parase('{"a":"hello","b":"world"}')
    // 结果:{a:'hello',b:'world'}
  • 要实现从JavaScript对象转换为JSON字符串,使用JSON.stringify()方法

    1
    2
    var json = JSON.STRINGIFY({a:'hello',b:'world'});
    // 结果:'{"a":"hello","b":"world"}'

简单测试

  1. 新建Modulespringmvc-06-json

  2. 新建jsonTest.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script>
    // 编写js对象 var -> let const
    let obj = {a:"hello",b:"world"}
    // 定义一个json字符串
    const json = '{"a":"hello","b":"world"}'

    // js对象转换 JSON
    console.log(JSON.stringify(obj))
    // JSON转换js对象
    console.log(JSON.parse(json))
    </script>
    </head>
    <body>

    </body>
    </html>
  3. 运行测试

    1
    2
    3
    4
    5
    6
    浏览器控制台显示
    {"a":"hello","b":"world"} //一个json字符串
    Object
    a: "hello"
    b: "world"
    [[Prototype]]: Object // js对象

Jackson使用

  • Jackson应该是目前比较好的json解析工具

  • 当然工具不止这一个,比如fastjson等

  • 这里使用Jackson,引入依赖

    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
    </dependency>
  • 配置SpringMVC需要的配置

    web.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <?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">
    <!-- DispatcherServlet-->
    <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: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>

    <!-- 过滤器-->
    <filter>
    <filter-name>EncodingFileter</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>EncodingFileter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    </web-app>
  • 新建springmvc-servlet.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <?xml version="1.0" encoding="UTF8"?>
    <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
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自动扫包-->
    <context:component-scan base-package="com.jokerdig.controller"/>
    <!-- 过滤静态资源-->
    <mvc:default-servlet-handler/>
    <!-- 支持注解驱动-->
    <mvc:annotation-driven/>

    <!--&lt;!&ndash; 视图解析器&ndash;&gt; -->
    <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)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.jokerdig.pojo;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    /**
    * @author Joker大雄
    * @data 2022/6/4 - 20:15
    **/
    // 需要导入lombok
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    private String name;
    private int age;
    private String sex;
    }
  • 这里我们要使用两个新东西,一个是@ResponseBody,一个是ObjectMapper对象,具体用法如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    package com.jokerdig.controller;

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.jokerdig.pojo.User;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;

    /**
    * @author Joker大雄
    * @data 2022/6/4 - 20:20
    **/
    @Controller
    // @RestController 该注解表示所有的方法都只返回字符串
    public class UserController {
    // 原始解决json乱码方法,springmvc可以通过配置一次性解决json乱码
    @RequestMapping(value="/j1",produces="application/json;charset=utf-8")
    @ResponseBody // 加这个注解就不会走视图解析器,会直接返回一个字符串
    public String json1() throws JsonProcessingException {

    // jackson ObjectMapper
    ObjectMapper mapper = new ObjectMapper();


    User user = new User("小王",18,"男");

    // 把一个Value转换为String
    String str = mapper.writeValueAsString(user);

    return str;
    }
    }
  • 运行后浏览器显示

    1
    {"name":"小王","age":18,"sex":"男"}

解决乱码问题优化

使用原始的方法较为繁琐,我们可以在springmvc配置文件统一配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF8"?>
<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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- 自动扫包-->
<context:component-scan base-package="com.jokerdig.controller"/>
<!-- 过滤静态资源-->
<mvc:default-servlet-handler/>
<!-- 支持注解驱动 解决乱码-->
<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>

<!--&lt;!&ndash; 视图解析器&ndash;&gt; -->
<bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>

</beans>

将之前配置的原始方法去掉,运行项目

1
{"name":"小王","age":18,"sex":"男"}

测试集合输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 测试集合的输出
@RequestMapping("/j2")
@ResponseBody // 加这个注解就不会走视图解析器,会直接返回一个字符串
public String json2() throws JsonProcessingException {

// jackson ObjectMapper
ObjectMapper mapper = new ObjectMapper();

List<User> list = new ArrayList<>();

User user1 = new User("小王1",18,"男");
User user2 = new User("小王2",18,"女");
User user3 = new User("小王3",18,"男");

list.add(user1);
list.add(user2);
list.add(user3);

// 把一个Value转换为String
String str = mapper.writeValueAsString(list);

return str;
}

运行结果

1
[{"name":"小王1","age":18,"sex":"男"},{"name":"小王2","age":18,"sex":"女"},{"name":"小王3","age":18,"sex":"男"}]

测试时间对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 测试时间对象的输出
@RequestMapping("/j3")
@ResponseBody // 加这个注解就不会走视图解析器,会直接返回一个字符串
public String json3() throws JsonProcessingException {

// jackson ObjectMapper 来格式化时间
ObjectMapper mapper = new ObjectMapper();
// 方法2 关闭默认显示时间戳
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);

// 方法2 使用自定义日期格式
SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(simp);

Date date = new Date();
// 方法1. 将时间戳转换为我们需要的格式
// SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// simp.format(date);

// 把一个Value转换为String
String str = mapper.writeValueAsString(date);

return str;
}

运行结果

1
"2022-06-04 21:08:39"

提取为工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.jokerdig.untils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
* @author Joker大雄
* @data 2022/6/4 - 21:09
**/
public class JsonUtils {
public static String getJson(Object object,String dateFormat){
// jackson ObjectMapper 来格式化时间
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;
}
}

调用工具类

1
2
3
4
5
6
7
8
9
// 传递时间
@RequestMapping("/j4")
@ResponseBody // 加这个注解就不会走视图解析器,会直接返回一个字符串
public String json4(){

Date date = new Date();

return new JsonUtils().getJson(date,"yyyy-MM-dd HH:mm:ss");
}

运行测试

1
"2022-06-04 21:18:48"