Java(SpringMVC02)

参考视频:8. Controller配置总结(狂神)

6. 控制器Controller和Restful风格

6.1 控制器Controller

  • 控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
  • 控制器负责解析用户的请求并将其转换为一个模型。
  • 在Spring MVC中一个控制器类可以包含多个方法。
  • 在Spring MVC中,对于Controller的配置方式有很多种。

6.2 实现Controller接口

  • Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法。
//实现该接口的类获得控制器功能
public interface Controller {//处理请求且返回一个模型与视图对象ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
  • 测试
  1. 新建一个Moudle,springmvc-04-controller 。将刚才的03 拷贝一份, 我们进行操作!
  • 删掉HelloController
  • mvc的配置文件只留下 视图解析器!
  • 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"><!--配置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></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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--这三个不写都行...--><!--扫描包--><context:component-scan base-package="com.zach.controller"/><!--过滤静态资源--><mvc:default-servlet-handler/><!--省去处理器适配器/处理器映射器的配置--><mvc:annotation-driven/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"><!--前缀--><property name="prefix" value="/WEB-INF/jsp/"/><!--后缀--><property name="suffix" value=".jsp"/></bean><bean name="/t1" class="com.zach.controller.ControllerTest1"/></beans>
  1. 编写一个Controller类,ControllerTest1
  • ControllerTest1
package com.zach.controller;import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;//定义控制器
//注意:不要导错包。当这个类实现了Controller接口,这就是一个控制器了。
public class ControllerTest1 implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {//返回一个模型视图对象ModelAndView mv = new ModelAndView();mv.addObject("msg","ControllerTest1");mv.setViewName("test");return mv;}
}
  1. 编写完毕后,去Spring配置文件中注册请求的bean。name对应请求路径,class对应处理请求的类。
<bean name="/t1" class="com.kuang.controller.ControllerTest1"/>
  1. 编写前端test.jsp,注意在WEB-INF/jsp目录下编写,对应我们的视图解析器。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Kuangshen</title>
</head>
<body>
${msg}
</body>
</html>
  1. 配置Tomcat运行测试,我这里没有项目发布名配置的就是一个/,所以请求不用加项目名,OK!
  • 说明:

    • 实现接口Controller定义控制器是较老的办法。
    • 缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller。定义的方式比较麻烦。

6.3 使用注解@Controller

  • @Controller注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解)。
@Component  //组件
@Service   //service
@Controller    //controller
@Repository    //dao
  • Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
<!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 -->
<context:component-scan base-package="com.kuang.controller"/>
  • 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><context:component-scan base-package="com.zach.controller"/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"><!--前缀--><property name="prefix" value="/WEB-INF/jsp/"/><!--后缀--><property name="suffix" value=".jsp"/></bean></beans>
  • 增加一个ControllerTest2类,使用注解实现。
  • ControllerTest2
package com.zach.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;//@Controller注解的类会自动添加到Spring上下文中
@Controller
//代表这个类会被Spring接管,这个被注解的类,
//  其中的所有方法,如果返回值是String,并且有具体页面可以跳转,
//  那么就会被视图解析器解析。
public class ControllerTest2 {//映射访问路径@RequestMapping("/t2")public String test1(Model model){//Spring MVC会自动实例化一个Model对象用于向视图中传值model.addAttribute("msg","ControllerTest2");//返回视图位置return "test";}
}
  • 运行tomcat测试
  • 可以发现,我们的两个请求都可以指向一个视图,但是页面上的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱耦合关系。
  • 注解方式是平时使用的最多的方式!

6.4 RequestMapping

  • @RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
  • 为了测试结论更加准确,我们可以加上一个项目名测试myweb(×)
package com.zach.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
//@RequestMapping("/c3")
public class ControllerTest3 {@RequestMapping("t1")public String test1(Model model){model.addAttribute("msg","ControllerTest3...t1");return "test";}@RequestMapping("/c3/t2")public String test2(Model model){model.addAttribute("msg","ControllerTest3.../c3/t2");return "test";}
}
  • 只注解在方法上面
  • 访问路径:http://localhost:8080/项目名/t1
@Controller
public class ControllerTest3 {@RequestMapping("/t1")public String test1(Model model){model.addAttribute("msg","ControllerTest3...t1");return "test";}
}
  • 同时注解类与方法
  • 访问路径:http://localhost:8080/项目名/c3/t1
@Controller
@RequestMapping("/c3")
public class ControllerTest3 {@RequestMapping("/t1")public String test1(Model model){model.addAttribute("msg","ControllerTest3...t1");return "test";}
}
  • 也可以写成:@RequestMapping("/c3/t1")
@Controller
public class ControllerTest3 {@RequestMapping("/c3/t1")public String test1(Model model){model.addAttribute("msg","ControllerTest3...t1");return "test";}
}

6.5 RestFul 风格

  • 概念

    • Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
  • 功能
    • 资源:互联网所有的事物都可以被抽象为资源
    • 资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
    • 分别对应 添加、 删除、修改、查询。
  • 传统方式操作资源: 通过不同的参数来实现不同的效果!方法单一,post 和 get
    • http://127.0.0.1/item/queryItem.action?id=1 查询,GET
    • http://127.0.0.1/item/saveItem.action 新增,POST
    • http://127.0.0.1/item/updateItem.action 更新,POST
    • http://127.0.0.1/item/deleteItem.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
  • 学习测试
  1. 再新建一个类 RestFulController
@Controller
public class RestFulController {}
  1. 在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量上。
@Controller
public class RestFulController {//映射访问路径@RequestMapping("/commit/{p1}/{p2}")public String index(@PathVariable int p1, @PathVariable int p2, Model model){int result = p1+p2;//Spring MVC会自动实例化一个Model对象用于向视图中传值model.addAttribute("msg", "结果:"+result);//返回视图位置return "test";}}
  • RestFulController
package com.zach.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;@Controller
public class RestFulController {//普通的风格:http://localhost:8080/add?a=1&b=1//RestFul风格:http://localhost:8080/add/1/2//http://localhost:8080/add/1/3@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.POST)public String test1(@PathVariable int a, @PathVariable String b, Model model){String res = a+b;model.addAttribute("msg","结果post为"+res);return "test";}//http://localhost:8080/add/1/2@GetMapping(value = "/add/{a}/{b}")public String test2(@PathVariable int a, @PathVariable String b, Model model){String res = a+b;model.addAttribute("msg","结果get为"+res);return "test";}}
  1. 测试

  2. 思考:使用路径变量的好处?

  • 使路径变得更加简洁。
  • 获得参数更加方便,框架会自动进行类型转换。
  • 通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如果这里访问是的路径是/add/1/a,则路径与方法不匹配,而不会是参数转换失败。
  1. 修改对应的参数类型,再次测试
  1. 使用method属性指定请求类型
  • 用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST,HEAD,OPTIONS,PUT,PATCH,DELETE,TRACE等
  • 我们来测试一下:
    • 增加一个方法
//映射访问路径,必须是POST请求
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
public String index2(Model model){model.addAttribute("msg", "hello!");return "test";
}
  • 我们使用浏览器地址栏进行访问默认是Get请求,会报错405

  • 如果将POST修改为GET则正常了

//映射访问路径,必须是Get请求
@RequestMapping(value = "/hello",method = {RequestMethod.GET})
public String index2(Model model){model.addAttribute("msg", "hello!");return "test";
}
  1. 小结:
  • Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法,比如 GET,PUT,POST,DELETE 以及 PATCH。
  • 所有的地址栏请求默认都会是 HTTP GET 类型的。
  • 方法级别的注解变体有如下几个:组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
  • @GetMapping 是一个组合注解,平时使用的会比较多!
  • 它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式。
  1. 扩展:小黄鸭调试法
  • 场景一: 我们都有过向别人(甚至可能向完全不会编程的人)提问及解释编程问题的经历,但是很多时候就在我们解释的过程中自己却想到了问题的解决方案,然后对方却一脸茫然。

  • 场景二: 你的同行跑来问你一个问题,但是当他自己把问题说完,或说到一半的时候就想出答案走了,留下一脸茫然的你。

  • 其实上面两种场景现象就是所谓的小黄鸭调试法(Rubber Duck Debuging),又称橡皮鸭调试法,它是我们软件工程中最常使用调试方法之一。

  • 此概念据说来自《程序员修炼之道》书中的一个故事,传说程序大师随身携带一只小黄鸭,在调试代码的时候会在桌上放上这只小黄鸭,然后详细地向鸭子解释每行代码,然后很快就将问题定位修复了。

7. 结果跳转方式

7.1 ModelAndView

  • 设置ModelAndView对象,根据view的名称,和视图解析器跳到指定的页面。
  • 页面 : {视图解析器前缀} + viewName + {视图解析器后缀}
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" />
</bean>
  • 对应的controller类
public class ControllerTest1 implements Controller {public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {//返回一个模型视图对象ModelAndView mv = new ModelAndView();mv.addObject("msg","ControllerTest1");mv.setViewName("test");return mv;}
}

7.2 ServletAPI方式(不重要)

  • 通过设置ServletAPI,不需要视图解析器。
  1. 通过HttpServletResponse进行输出
  2. 通过HttpServletResponse实现重定向
  3. 通过HttpServletResponse实现转发
@Controller
public class ResultGo {@RequestMapping("/result/t1")public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {rsp.getWriter().println("Hello,Spring BY servlet API");}@RequestMapping("/result/t2")public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {rsp.sendRedirect("/index.jsp");}@RequestMapping("/result/t3")public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {//转发req.setAttribute("msg","/result/t3");req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);}}

7.3 SpringMVC方式

  1. 通过SpringMVC来实现转发和重定向 - 无需视图解析器。
  • 测试前,需要将视图解析器注释掉
@Controller
public class ResultSpringMVC {@RequestMapping("/rsm/t1")public String test1(){//转发return "/index.jsp";}@RequestMapping("/rsm/t2")public String test2(){//转发二return "forward:/index.jsp";}@RequestMapping("/rsm/t3")public String test3(){//重定向return "redirect:/index.jsp";}
}
  1. 通过SpringMVC来实现转发和重定向 - 有视图解析器。
  • 重定向,不需要视图解析器,本质就是重新请求一个新地方嘛 ,所以注意路径问题。
  • 可以重定向到另外一个请求实现。
@Controller
public class ResultSpringMVC2 {@RequestMapping("/rsm2/t1")public String test1(){//转发return "test";}@RequestMapping("/rsm2/t2")public String test2(){//重定向return "redirect:/index.jsp";//return "redirect:hello.do"; //hello.do为另一个请求/}}

8. 数据处理

8.1 处理提交数据

  1. 提交的域名称和处理方法的参数名 一致
  • 提交数据 : http://localhost:8080/hello?name=kuangshen
  • 处理方法 :
@RequestMapping("/hello")
public String hello(String name){System.out.println(name);return "hello";
}
  • 后台输出 : kuangshen
  1. 提交的域名称和处理方法的参数名 不一致
  • 提交数据 : http://localhost:8080/hello?username=kuangshen
  • 处理方法 :
//@RequestParam("username") : username提交的域的名称 .
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){System.out.println(name);return "hello";
}
  • 后台输出 : kuangshen
  1. 提交的是一个对象
  • 要求提交的表单域和对象的属性名一致 , 参数使用对象即可
  • 1.实体类
public class User {private int id;private String name;private int age;//构造//get/set//tostring()
}
  • 2.提交数据: http://localhost:8080/mvc04/user?name=kuangshen&id=1&age=15
  • 3.处理方法 :
@RequestMapping("/user")
public String user(User user){System.out.println(user);return "hello";
}
  • 后台输出 : User { id=1, name=‘kuangshen’, age=15 }
  • 说明:如果使用对象的话,前端传递的参数名和对象名必须一致,否则就是null。

8.2 数据显示到前端

8.2.1 第一种 : 通过ModelAndView

  • 我们前面一直都是如此 . 就不过多解释
public class ControllerTest1 implements Controller {public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {//返回一个模型视图对象ModelAndView mv = new ModelAndView();mv.addObject("msg","ControllerTest1");mv.setViewName("test");return mv;}
}

8.2.2 第一种 : 通过ModelMap

  • ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){//封装要显示到视图中的数据//相当于req.setAttribute("name",name);model.addAttribute("name",name);System.out.println(name);return "hello";
}

8.2.3 第一种 : 通过Model

  • Model
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){//封装要显示到视图中的数据//相当于req.setAttribute("name",name);model.addAttribute("msg",name);System.out.println(name);return "test";
}

8.3 对比

  • 就对于新手而言简单来说使用区别就是:
Model    只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;ModelMap   继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;ModelAndView    可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
  • 当然更多的以后开发考虑的更多的是性能和优化,就不能单单仅限于此的了解。
  • 请使用80%的时间打好扎实的基础,剩下18%的时间研究框架,2%的时间去学点英文,框架的官方文档永远是最好的教程。

8.4 乱码问题

测试步骤:

  1. 我们可以在首页编写一个提交的表单
<form action="/e/t" method="post"><input type="text" name="name"><input type="submit">
</form>
  1. 后台编写对应的处理类
@Controller
public class Encoding {@RequestMapping("/e/t")public String test(Model model,String name){model.addAttribute("msg",name); //获取表单提交的值return "test"; //跳转到test页面显示输入的值}
}
  1. 输入中文测试,发现乱码
  • 不得不说,乱码问题是在我们开发中十分常见的问题,也是让我们程序猿比较头大的问题!
  • 以前乱码问题通过过滤器解决,而SpringMVC给我们提供了一个过滤器,可以在web.xml中配置。
  • 修改了xml文件需要重启服务器!
 <!--2. 配置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>
  • 但是我们发现,有些极端情况下,这个过滤器对get的支持不好。
  • 其他处理方法 :
  1. 修改tomcat配置文件 :设置编码!
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />
  1. 自定义过滤器(解决get和post请求 全部乱码的过滤器)
package com.kuang.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 {@Overridepublic void destroy() {}@Overridepublic 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);}@Overridepublic 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;}// 对需要增强方法 进行覆盖@Overridepublic 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();}//取一个值@Overridepublic String getParameter(String name) {Map<String, String[]> parameterMap = getParameterMap();String[] values = parameterMap.get(name);if (values == null) {return null;}return values[0]; // 取回参数的第一个值}//取所有值@Overridepublic String[] getParameterValues(String name) {Map<String, String[]> parameterMap = getParameterMap();String[] values = parameterMap.get(name);return values;}
}
  • 这个也是在网上找的一些大神写的,一般情况下,SpringMVC默认的乱码处理就已经能够很好的解决了!
  • 然后在web.xml中 配置 这个过滤器即可!
  • 乱码问题,需要平时多注意,在尽可能能设置编码的地方,都设置为统一编码 UTF-8!

9. JSON

9.1 什么是JSON?

  • JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的 数据交换格式 ,目前使用特别广泛。
  • 采用完全独立于编程语言的文本格式来存储和表示数据。
  • 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
  • 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
  • 在 JavaScript 语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。看看他的要求和语法格式:
    • 对象表示为键值对,数据由逗号分隔
    • 花括号保存对象
    • 方括号保存数组
  • JSON 键值对是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:
    {“name”: “QinJiang”}
    {“age”: “3”}
    {“sex”: “男”}

  • 很多人搞不清楚 JSON 和 JavaScript 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:

    • 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"}'
  • 代码测试:
  1. 新建一个module ,springmvc-05-json , 添加web的支持
  2. 在web目录下新建一个 json-1.html , 编写测试内容
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>JSON_秦疆</title>
</head>
<body><script type="text/javascript">//编写一个js的对象var user = {name:"秦疆",age:3,sex:"男"};//将js对象转换成json字符串var str = JSON.stringify(user);console.log(str);//将json字符串转换为js对象var user2 = JSON.parse(str);console.log(user2.age,user2.name,user2.sex);</script></body>
</html>
  1. 在IDEA中使用浏览器打开,查看控制台输出!

9.2 Controller返回JSON数据

  • Jackson应该是目前比较好的json解析工具了
  • 当然工具不止这一个,比如还有阿里巴巴的 fastjson 等
  • 我们这里使用Jackson,使用它需要导入它的jar包
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.0</version>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version>
</dependency>
  • 配置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"><!--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><!--2. 所有请求都会被springmvc拦截 --><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>
  • 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><context:component-scan base-package="com.zach.controller"/><!-- 视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean></beans>
  • 我们随便编写一个User的实体类,然后我们去编写我们的测试Controller
package com.zach.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;//需要导入lombok
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private String name;private int age;private String sex;
}
  • 这里我们需要两个新东西,一个是@ResponseBody,一个是ObjectMapper对象,我们看下具体的用法。
  • 编写一个Controller
//@Controller   //它会走视图解析器
@RestController //它会直接返回一个字符串
public class UserController {@RequestMapping("/j1")//@ResponseBody   //加上该注解,它就不会走视图解析器了,会直接返回一个字符串。如果上面用了@RestController,这里就不需要了。public String json1() throws JsonProcessingException {//jackson, ObjectMapperObjectMapper mapper = new ObjectMapper();//创建一个对象User user = new User("张天道1",18,"男");String str = mapper.writeValueAsString(user);return str;}
}
  • 配置Tomcat , 启动测试一下!
  • http://localhost:8080/j1

  • 发现出现了乱码问题,我们需要设置一下他的编码格式为utf-8,以及它返回的类型。
  • 通过@RequestMaping的produces属性来实现,修改下代码。
//produces:指定响应体返回类型和编码
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
  • 再次测试, http://localhost:8080/json1 , 乱码问题OK!
  • 【注意:使用json记得处理乱码问题】

9.3 乱码统一解决

  • 上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!
  • 我们可以在springmvc的配置文件上添加一段消息StringHttpMessageConverter转换配置!
  • springmvc-servlet.xml
<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>

9.4 返回json字符串统一解决

  • 在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!
@RestController
public class UserController {//produces:指定响应体返回类型和编码@RequestMapping(value = "/json1")public String json1() throws JsonProcessingException {//创建一个jackson的对象映射器,用来解析数据ObjectMapper mapper = new ObjectMapper();//创建一个对象User user = new User("秦疆1号", 3, "男");//将我们的对象解析成为json格式String str = mapper.writeValueAsString(user);//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便return str;}}
  • 启动tomcat测试,结果都正常输出!

9.5 测试集合输出

  • 增加一个新的方法
@RequestMapping("/json2")
public String json2() throws JsonProcessingException {//创建一个jackson的对象映射器,用来解析数据ObjectMapper mapper = new ObjectMapper();//创建一个对象User user1 = new User("秦疆1号", 3, "男");User user2 = new User("秦疆2号", 3, "男");User user3 = new User("秦疆3号", 3, "男");User user4 = new User("秦疆4号", 3, "男");List<User> list = new ArrayList<User>();list.add(user1);list.add(user2);list.add(user3);list.add(user4);//将我们的对象解析成为json格式String str = mapper.writeValueAsString(list);return str;
}
  • 运行结果 : 十分完美,没有任何问题!

9.6 输出时间对象

  • 增加一个新的方法
@RequestMapping("/json3")
public String json3() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();//创建时间一个对象,java.util.DateDate date = new Date();//将我们的对象解析成为json格式String str = mapper.writeValueAsString(date);return str;
}
  • 默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数!
  • Jackson 默认是会把时间转成timestamps形式的。

  • 解决方案:取消timestamps形式 , 自定义时间格式
@RequestMapping("/json4")
public String json4() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();//不使用时间戳的方式mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//自定义日期格式对象SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//指定日期格式mapper.setDateFormat(sdf);Date date = new Date();String str = mapper.writeValueAsString(date);return str;
}
  • 运行结果 : 成功的输出了时间!

9.7 抽取为工具类

  • 如果要经常使用的话,这样是比较麻烦的,我们可以将这些代码封装到一个工具类中;我们去编写下
  • JsonUtils(包括一个重载方法)
package com.zach.utils;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;import java.text.SimpleDateFormat;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;}
}
  • 我们使用工具类,代码就更加简洁了!
@RequestMapping("/json5")
public String json5() throws JsonProcessingException {Date date = new Date();String json = JsonUtils.getJson(date);return json;
}
  • 大功告成!完美!

9.8 FastJson

  • fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。
  • fastjson 的 pom依赖!
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.60</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字符串之间的相互转化。

  • 代码测试,我们新建一个FastJsonDemo 类
  • 记得在打包目录下的lib里加个包
package com.kuang.controller;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kuang.pojo.User;import java.util.ArrayList;
import java.util.List;public class FastJsonDemo {public static void main(String[] args) {//创建一个对象User user1 = new User("秦疆1号", 3, "男");User user2 = new User("秦疆2号", 3, "男");User user3 = new User("秦疆3号", 3, "男");User user4 = new User("秦疆4号", 3, "男");List<User> list = new ArrayList<User>();list.add(user1);list.add(user2);list.add(user3);list.add(user4);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);}
}
  • 这种工具类,我们只需要掌握使用就好了,在使用的时候在根据具体的业务去找对应的实现。和以前的commons-io那种工具包一样,拿来用就好了!

  • Json在我们数据传输中十分重要,一定要学会使用!

—————— THE END ——————

Java(SpringMVC02)相关推荐

  1. MongoDB和Java(4):Spring Data整合MongoDB(XML配置)

    最近花了一些时间学习了下MongoDB数据库,感觉还是比较全面系统的,涉及了软件安装.客户端操作.安全认证.副本集和分布式集群搭建,以及使用Spring Data连接MongoDB进行数据操作,收获很 ...

  2. Effective Java(1)-创建和销毁对象

    Effective Java(1)-创建和销毁对象 转载于:https://www.cnblogs.com/Johar/p/10556218.html

  3. 菜鸟学Java(六)——简单验证码生成(Java版)

    转载自  菜鸟学Java(六)--简单验证码生成(Java版) 验证码大家都知道,它的作用也不用我多说了吧.如果不太清楚请参见百度百科中的解释,一般验证码的生成就是随机产生字符(数字.字母或者汉字等) ...

  4. Java(enum)枚举用法详解

    转载自 Java(enum)枚举用法详解 本篇文章主要介绍了Java 枚举用法详解,枚举的好处:可以将常量组织起来,统一进行管理.有兴趣的可以一起来了解一下. 概念 enum的全称为 enumerat ...

  5. MongoDB和Java(5):Spring Data整合MongoDB(注解配置)

    最近花了一些时间学习了下MongoDB数据库,感觉还是比较全面系统的,涉及了软件安装.客户端操作.安全认证.副本集和分布式集群搭建,以及使用Spring Data连接MongoDB进行数据操作,收获很 ...

  6. appium+java(五)微信小程序自动化测试实践

    前言: 上一篇<appium+java(四)微信公众号自动化测试实践>中,尝试使用appium实现微信公众号自动化测试,接着尝试小程序自动化,以学院小程序为例 准备工作 1.java-cl ...

  7. 【零基础学Java】—初识Java(一)

    [零基础学Java]- 初识Java(一)

  8. 零学Java(7)之数据类型,小AD竟然solo不过小朋友

    作者简介 本文章为转载,原作者名:编程界明世隐,仅用来学习 简介:CSDN博客专家,从事软件开发多年,精通Java.JavaScript,博主也是从零开始一步步把学习成长.深知学习和积累的重要性,喜欢 ...

  9. 小闫陪你入门 Java (三)

    意气风发啊骑上我快乐的小摩托良心公众号啊!我上墙了你开始了嚯嚯嚯嚯嚯哈哈哈哈哈皮皮虾我们走可乐在厨房 红牛在冰箱6666666 看弹幕,点关注 " First say to yourself ...

最新文章

  1. 生产环境实用的小脚本
  2. 用top方法查看内存消耗的方法
  3. sql 关联使用id还是code_R语言实例:用glue批量生成SQL语句
  4. 可以直接考甲级吗_函授本科可以考四级吗
  5. UDP聊天小程序+多线程(Python)
  6. ROS笔记(20) Kinect仿真
  7. java怎么定义范围_java – Dagger自定义范围,怎么办?
  8. Android使用Http访问网络
  9. Windows下安装和配置Kibana
  10. LSTM+attention代码原理详解
  11. 【转】什么是Online Learning
  12. css中如何使图标的旋转
  13. Algorithms, Part I by Kevin Wayne, Robert Sedgewick
  14. KF、EKF、IEKF、UKF卡尔曼滤波器
  15. C#快速调用海康威视工业相机的SDK拍照获取图片
  16. 使用苹果发布证书打包好的ipa如何安装到ios手机上测试
  17. 游戏服务器和网站,大型网络游戏和大型网站需要服务器的不同
  18. android studio天气预报
  19. char* p 和 char p[]区别及应用
  20. 数据泄漏检测和溯源技术

热门文章

  1. 代码!以备不时之需!中文文本预处理(停用词、空格分隔、按行分类)
  2. SQL快出来,收快递啦(分区,case when 连表)
  3. 后台管理系统----day02
  4. Photoshop学习(三十六):去除图中的灰雾
  5. 11_SysTick定时器
  6. 打破部门墙的6个高效沟通方法
  7. 我如何用前端技术得到XXOO网站的VIP
  8. 美客多卖家攻略:养号技巧分享
  9. Linux静态库与动态库的相关概念以及编程
  10. Java毕设项目大型商场应急预案管理系统(java+VUE+Mybatis+Maven+Mysql)