五、Rest风格编程
(一)Rest风格URL规范介绍
1、什么是restful
RESTful架构,就是目前最流行的一种互联网软件架构风格。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的. Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。即"表现层状态转化"。如果一个架构符合REST原则,就称它为RESTful架构。值得注意的是 REST 并没有一个明确的标准,而更像是一种设计的格。
它本身并没有什么实用性,其核心价值在于如何设计出符合 REST 风格的网络接口。
2、restful的优点:
它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
3、restful 的特性:
(1)资源(Resources)
网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符。
(2)表现层(Representation)
把资源具体呈现出来的形式,叫做它的表现层 (Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
(3)状态转化(State Transfer)
每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP 协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是“表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET 、POST 、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
(4)传统请求url
新增:http://localhost:8888/annotation/addPerson POST
修改:http://localhost:8888/annotation/updatePerson POST
删除:http://localhost:8888/annotation/deletePerson?id=1 GET
查询:http://localhost:8888/annotation/findPerson?id=1 GET
(4)REST风格请求
新增:http://localhost:8888/annotation/person POST
修改:http://localhost:8888/annotation/person PUT
删除:http://localhost:8888/annotation/person/1 DELETE
查询:http://localhost:8888/annotation/person/1 GET
(二)PathVariable注解详解
该注解用于绑定 url 中的占位符。例如:请求 url 中/annotation/test9/{id},这个{id}就是 url 占位符。url 支持占位符是 spring3.0 之后加入的。是springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
(三)PathVariable案例
1、构建页面发起请求
REST风格编程:
增删改查
<h2>REST风格编程</h2>
<br>
新增:
<form action="person" method="post">name :<input type="text" name="name"><br>age :<input type="text" name="age"><br><input type="submit" value="提交">
</form>
<br>修改:
<form action="person" method="post"><input type="hidden" name="_method" value="put">name :<input type="text" name="name"><br>age :<input type="text" name="age"><br><input type="submit" value="提交">
</form>
<br>
删除:
<form action="person/1" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="提交">
</form>
<br>
查询:
<a href="person/1">查询</a>
2、定义控制层执行器处理请求
//测试添加@RequestMapping(value = "user", method = RequestMethod.POST)public String addUser(String name,int age){System.out.println("新增用户:" + name+"\t"+age);return "RequestSuccessful";}//测试修改@RequestMapping(value = "user", method = RequestMethod.PUT)public String updateUser(String name,int age){System.out.println("修改用户:" + name+"\t"+age);return "RequestSuccessful";}//测试删除@RequestMapping(value = "user/{id}", method = RequestMethod.DELETE)public String deleteUser(@PathVariable(value = "id")int id){System.out.println("删除用户:" + id);return "RequestSuccessful";}//查询用户@RequestMapping(value = "user/{id}", method = RequestMethod.GET)public String getUser(@PathVariable(value = "id")int id){System.out.println("查询用户:" + id);return "RequestSuccessful";}
3.测试出现错误
4.引入请求方式转换过滤器
<filter><filter-name>hiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter>
<filter-mapping><filter-name>hiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
5.双出现错误
类型 状态报
消息 JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS
描述 请求行中接收的方法由源服务器知道,但目标资源不支持
Apache Tomcat/8.5.85
6.再解决错误
在JSP文件的page标签中添加:isErrorPage=“true”
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isErrorPage="true" %>
7.双又错啦
但是丝毫不影响测试结果,查阅资料显示Tomcat的版本太高,内部抛弃了那些什么某种约束不允许除了get\post以外的请求方式,但是不影响测试。
8.测试结果
六、响应数据和结果视图
(一)返回值分类
1、返回值为字符串
用于指定返回的逻辑视图名称;
控制器代码:
//测试返回值为字符串类型@RequestMapping("testString")public String testString(){System.out.println("返回String类型测试");return "RequestSuccessful";}
运行结果:
2、void类型
通常使用原始servlet处理请求时,返回该类型;
控制器代码:
//测试返回值类型为void类型@RequestMapping("testVoid")public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("返回void类型测试");request.getRequestDispatcher("/testString").forward(request,response);}
运行结果:
3、ModelAndView
用于绑定参数和指定返回视图名称;
控制器代码:
//返回ModelAndView类型测试@RequestMapping("testModelAndView")public ModelAndView testModelAndView(ModelAndView mv){mv.addObject("aa","AA");mv.setViewName("RequestSuccessful");return mv;}
JSP页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
<h2>请求处理成功</h2>
<h2>a:${requestScope.aa}</h2>
</body>
</html>
运行结果:
(二)转发和重定向
1、forward请求转发
控制器代码:
//forword请求转发测试@RequestMapping("testForward")public String testForward(){System.out.println("请求转发");return "forward:/testString";}
运行结果:
2、redirect重定向
控制器代码:
//redirect重定向测试@RequestMapping("testRedirect")public String testRedirect(){System.out.println("请求重定向");return "redirect:http://www.baidu.com";}
运行结果:
3、携带参数的重定向
控制器代码:
//携带参数的重定向测试@RequestMapping("testRedirectWithParam")public String testRedirectWithParam(RedirectAttributes ra,String name){System.out.println("携带参数的重定向");ra.addAttribute("name",name);//访问的参数在进行重定向的时候会被显示//ra.addFlashAttribute("name",name);return "redirect:/testRedirectParam";}//接收重定向请求参数的测试案例@RequestMapping("testRedirectParam")public String testRedirectParam(String name){System.out.println("接收重定向请求参数");System.out.println(name);return "RequestSuccessful";}
运行结果:
注意:重定向携带参数,需要使用对象RedirectAttributes,该对象提供两个方法封装参数addAttribute()和addFlashAttribute(),第一个方法参数会明文显示在浏览器地址栏,第二个方法参会会隐藏,使用第二种方法传参时,获取参数时需要加注解@ModelAttribute;
//接收重定向请求参数的测试案例@RequestMapping("testRedirectParam")public String testRedirectParam(@ModelAttribute(value = "name") String name) {System.out.println("接收重定向请求参数");System.out.println(name);return "RequestSuccessful";}
(三)ResponseBody 响应 json 数据
1、ResponseBody使用介绍
@ResponseBody的作用其实是将java对象转为json格式的数据。
2、ResponseBody使用案例:
(1)引入json相关依赖
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency>
(2)编写jsp页面,发送异步请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/2.2.0/jquery.min.js"></script></head>
<body>
<button id="btn">发送ajax请求</button><button onclick="getUser()">获得json数据</button><script>//页面加载时间$(function () {//为按钮绑定点击事件$("#btn").click(function () {$.ajax({url: "ajaxTest",data: '{"name":"Tom","age":18}',type: "POST",contentType: "application/json",success: function (obj) {//将控制层操作成功响应信息通过弹窗展示alert(obj);},})})});function getUser() {$.ajax({type: "GET",url: "jsonTest",dataType: "json", // 添加这一行,明确指定期望的响应数据类型为JSONsuccess: function (msg) {alert("Data Saved: " + msg);}});}
</script></body>
</html>
(3)编写控制器方法添加ResponseBody注解
//获取json数据的测试@RequestMapping("jsonTest")@ResponseBodypublic User testJson(){User user = new User();user.setName("张三");user.setAge(20);Car car = new Car();car.setName("奔驰");car.setPrice(100000);user.setCar(car);return user;}
(4)测试出现错误
GET http://localhost:8080/SpringMVC01_war_exploded/jsonTest 406 (Not Acceptable)
(5)解决了一上午的错误
发现是Springmvc配置文件里面多配置了两个处理器映射器以及处理器适配器,如图:
(6)修改完成后的配置
<?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.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--扫描注解的包--><context:component-scan base-package="com.jn"/><!--视图解析器:解析视图--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean><!-- 配置 Web 数据绑定 --><mvc:annotation-driven conversion-service="conversionService"><mvc:message-converters><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></mvc:message-converters></mvc:annotation-driven><!--开启静态资源配置 第一种方式<mvc:default-servlet-handler></mvc:default-servlet-handler>
--><!--开启静态资源配置 第二种方式--><mvc:resources mapping="/images/**" location="/images/"/><!--配置类型转换器
将自定义的 MyDateConverter 注册到 Spring 的类型转换服务中,使得在应用中可以使用 MyDateConverter 来进行字符串到日期的转换。--><bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><set><bean class="com.jn.utils.MyDateConverter" /></set></property></bean></beans>
(7)终极测试
七、Postman工具使用
(一)Postman工具介绍
用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。今天给大家介绍的这款网页调试工具不仅可以调试简单的css、html、脚本等简单的网页基本信息,它还可以发送几乎所有类型的HTTP请求!Postman在发送网络HTTP请求方面可以说是Chrome插件类产品中的代表产品之一。
(二)Postman工具的下载安装
1、下载地址:https://www.postman.com/downloads/
2、安装步骤:
(1)下载安装文件
(2)运行安装程序
(3)重启电脑自动安装
(4)运行
(三)Postman工具的使用
1、启动Tomcat服务器
2、打开postMan新建连接
3、测试添加
4、测试修改
5、测试删除
6、测试查询
八、SpringMVC中的父子容器解析
(一)SpringMVC中的父子容器解析
Spring和SpringMVC的容器具有父子关系。Spring容器为父容器,SpringMVC为子容器,子容器可以引用父容器中的Bean,而父容器不可以引用子容器中的Bean。
配置spring的配置文件时,排出扫描控制层注解:
<context:component-scan base-package="com.jn"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
配置springMVC的配置文件时,扫描控制层注解:
<context:component-scan base-package="com.jn.controller"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
九、SpringMVC中的文件上传
(一)文件上传的必要前提:
1、form 表单的 enctype 取值必须是multipart/form-data(默认值是:application/x-www-form-urlencoded)enctype:是表单请求正文的类型
2、 method 属性取值必须是 Post
3、提供一个文件选择域<input type=”file”/>
(二)文件上传原理分析
当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是: key=value&key=value&key=value;
当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成: 每一部分都是 MIME 类型描述的正文;
(三)SpringMVC的文件上传
1、构建maven工程添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.jn</groupId><artifactId>SpringMVC02</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>SpringMVC02 Maven Webapp</name><url>http://maven.apache.org</url><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!--spring-webmvc--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.4</version></dependency><!--spring-web--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.3.4</version></dependency><!--spring-context--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.4</version></dependency><!--servlet-api依赖--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency><!--fileupload --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version></dependency></dependencies><build><finalName>SpringMVC02</finalName></build>
</project>
2、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/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.jn"></context:component-scan><!--视图解析器:解析视图--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean><!-- 配置 Web 数据绑定 --><mvc:annotation-driven conversion-service="conversionService"><mvc:message-converters><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></mvc:message-converters></mvc:annotation-driven><!--配置类型转换器
将自定义的 MyDateConverter 注册到 Spring 的类型转换服务中,使得在应用中可以使用 MyDateConverter 来进行字符串到日期的转换。--><bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean></beans>
3、web.xml文件的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><!-- 配置Spring MVC的前端控制器 --><servlet><!-- servlet的名称 --><servlet-name>spring-mvc</servlet-name><!-- servlet的类路径,指向Spring的请求分发器 --><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 初始化参数,指定Spring MVC配置文件的位置 --><init-param><!-- 参数名称:配置文件位置 --><param-name>contextConfigLocation</param-name><!-- 参数值:配置文件在类路径下的位置 --><param-value>classpath:SpringMVC.xml</param-value></init-param></servlet><!-- 配置spring-mvc servlet的URL映射规则 --><servlet-mapping><!-- 对应的servlet名称 --><servlet-name>spring-mvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!--配置post请求时的编码过滤器--><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><!--引入请求方式转换过滤器--><!-- 配置HiddenHttpMethodFilter --><filter><filter-name>HiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter><filter-mapping><filter-name>HiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>
4、编写 jsp 页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isErrorPage="true" %>
<html>
<head>
</head>
<body>
<form action="upload" method="post" enctype="multipart/form-data"><input type="file" name="file"/><input type="submit" value="上传"/>
</form></body>
</html>
6、编写控制器
package com.jn.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;import java.io.File;@Controller
public class FileController {//测试文件上传@RequestMapping("upload")public String upload(MultipartFile file){File dest = new File("C:/photos/"+file.getOriginalFilename());try {file.transferTo(dest);} catch (Exception e) {e.printStackTrace();}return "successful";}}
6、配置文件解析器
<!--配置文件解析器--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
7、测试文件上传的运行结果
十、SpringMVC中的异常处理
(一)项目开发中异常处理的方式介绍
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
(二)异常处理的设计思路
系统的 dao、service、controller出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。
(三)异常处理的步骤
1、编写异常类和错误页面
//测试异常处理@RequestMapping("error")public String error(){System.out.println("error");int a = 1/0;return "error";}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<style>@import url('https://fonts.googleapis.com/css?family=Montserrat:400,600,700');@import url('https://fonts.googleapis.com/css?family=Catamaran:400,800');.error-container {text-align: center;font-size: 106px;font-family: 'Catamaran', sans-serif;font-weight: 800;margin: 70px 15px;}.error-container > span {display: inline-block;position: relative;}.error-container > span.four {width: 136px;height: 43px;border-radius: 999px;background:linear-gradient(140deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.07) 43%, transparent 44%, transparent 100%),linear-gradient(105deg, transparent 0%, transparent 40%, rgba(0, 0, 0, 0.06) 41%, rgba(0, 0, 0, 0.07) 76%, transparent 77%, transparent 100%),linear-gradient(to right, #d89ca4, #e27b7e);}.error-container > span.four:before,.error-container > span.four:after {content: '';display: block;position: absolute;border-radius: 999px;}.error-container > span.four:before {width: 43px;height: 156px;left: 60px;bottom: -43px;background:linear-gradient(128deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.07) 40%, transparent 41%, transparent 100%),linear-gradient(116deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.07) 50%, transparent 51%, transparent 100%),linear-gradient(to top, #99749D, #B895AB, #CC9AA6, #D7969E, #E0787F);}.error-container > span.four:after {width: 137px;height: 43px;transform: rotate(-49.5deg);left: -18px;bottom: 36px;background: linear-gradient(to right, #99749D, #B895AB, #CC9AA6, #D7969E, #E0787F);}.error-container > span.zero {vertical-align: text-top;width: 156px;height: 156px;border-radius: 999px;background: linear-gradient(-45deg, transparent 0%, rgba(0, 0, 0, 0.06) 50%, transparent 51%, transparent 100%),linear-gradient(to top right, #99749D, #99749D, #B895AB, #CC9AA6, #D7969E, #ED8687, #ED8687);overflow: hidden;animation: bgshadow 5s infinite;}.error-container > span.zero:before {content: '';display: block;position: absolute;transform: rotate(45deg);width: 90px;height: 90px;background-color: transparent;left: 0px;bottom: 0px;background:linear-gradient(95deg, transparent 0%, transparent 8%, rgba(0, 0, 0, 0.07) 9%, transparent 50%, transparent 100%),linear-gradient(85deg, transparent 0%, transparent 19%, rgba(0, 0, 0, 0.05) 20%, rgba(0, 0, 0, 0.07) 91%, transparent 92%, transparent 100%);}.error-container > span.zero:after {content: '';display: block;position: absolute;border-radius: 999px;width: 70px;height: 70px;left: 43px;bottom: 43px;background: #FDFAF5;box-shadow: -2px 2px 2px 0px rgba(0, 0, 0, 0.1);}.screen-reader-text {position: absolute;top: -9999em;left: -9999em;}@keyframes bgshadow {0% {box-shadow: inset -160px 160px 0px 5px rgba(0, 0, 0, 0.4);}45% {box-shadow: inset 0px 0px 0px 0px rgba(0, 0, 0, 0.1);}55% {box-shadow: inset 0px 0px 0px 0px rgba(0, 0, 0, 0.1);}100% {box-shadow: inset 160px -160px 0px 5px rgba(0, 0, 0, 0.4);}}/* demo stuff */* {-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;}body {background-color: #FDFAF5;margin-bottom: 50px;}html, button, input, select, textarea {font-family: 'Montserrat', Helvetica, sans-serif;color: #bbb;}h1 {text-align: center;margin: 30px 15px;}.zoom-area {max-width: 490px;margin: 30px auto 30px;font-size: 19px;text-align: center;}.link-container {text-align: center;}a.more-link {text-transform: uppercase;font-size: 13px;background-color: #de7e85;padding: 10px 15px;border-radius: 0;color: #fff;display: inline-block;margin-right: 5px;margin-bottom: 5px;line-height: 1.5;text-decoration: none;margin-top: 50px;letter-spacing: 1px;}
</style>
<body>
<h1>404 Error Page #2</h1>
<p class="zoom-area"><b>CSS</b> animations to make a cool 404 page. </p>
<section class="error-container"><span class="four"><span class="screen-reader-text">4</span></span><span class="zero"><span class="screen-reader-text">0</span></span><span class="four"><span class="screen-reader-text">4</span></span>
</section>
<div class="link-container"><a target="_blank" href="https://www.silocreativo.com/en/creative-examples-404-error-css/" class="more-link">Visit the original article</a>
</div></body>
</html>
2、自定义异常处理器
package com.jn.utils;import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyExceptionHandler implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {e.printStackTrace();System.out.println("自定义异常处理");ModelAndView mv = new ModelAndView();mv.setViewName("error");return mv;}
}
3、配置异常处理器
<!--配置自定义的异常处理器--><bean class="com.jn.utils.MyExceptionHandler"></bean>
4、测试异常处理的运行结果
十一、SpringMVC中的拦截器使用
(一)拦截器的介绍和作用
SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
(二)拦截器与过滤器的区别:
过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。拦截器是 SpringMVC 框架自己的,只有使用了SpringMVC框架的工程才能用。过滤器在web.xml中的 url-pattern 标签中配置了/*之后,可以对所有要访问的资源拦截。拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者js是不会进行拦截的。它也是 AOP 思想的具体应用。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
(三)自定义拦截器的步骤
1、编写一个普通类实现 HandlerInterceptor 接口
package com.jn.utils;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {//控制层执行之前的拦截器@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("控制层执行之前的拦截器");return true;}//控制层执行器方法返回时拦截器@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("控制层执行器方法返回时拦截器");}//控制层结束之后的拦截器@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("控制层结束之后的拦截器");}
}
2、配置拦截器
<!--配置SpringMVC的拦截器--><mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.jn.utils.MyInterceptor"></bean></mvc:interceptor></mvc:interceptors>
3、测试拦截器的运行结果
随便执行一个方法
(四)拦截器的注意事项
1、拦截器的放行
拦截器中的放行指的是:如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)方法返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法。
2、拦截器中方法的说明
preHandle方法说明
控制层执行之前的拦截器。
改方法在控制层执行器方法前调用,该方法返回结果为true则继续调用下一个拦截器。
改方法返回结果为false则不会调用下一个拦截器,也不会调用控制层执行器方法。
/*控制层执行之前的拦截器。改方法在控制层执行器方法前调用,该方法返回结果为true则继续调用下一个拦截器。改方法返回结果为false则不会调用下一个拦截器,也不会调用控制层执行器方法。*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("控制层执行之前的拦截器");return true;}
postHandle方法说明
控制层执行器方法返回时拦截器 该方法在控制层执行器方法返回时调用,由DispatcherServlet在将结果响应给浏览器前的调用。
/*控制层执行器方法返回时拦截器该方法在控制层执行器方法返回时调用,由DispatcherServlet在将结果响应给浏览器前的调用。*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("控制层执行器方法返回时拦截器");}
afterCompletion方法说明
控制层结束之后的拦截器 该方法在DispatcherServlet将结果响应给浏览器后调用。
/*控制层结束之后的拦截器该方法在DispatcherServlet将结果响应给浏览器后调用。*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("控制层结束之后的拦截器");}
3、拦截器的作用路径
<!--配置SpringMVC的拦截器--><!--用于定义一组拦截器--><mvc:interceptors><!--定义一个具体的拦截器--><mvc:interceptor><!--指定拦截器应用的路径。/** 表示拦截所有路径--><mvc:mapping path="/**"/><!--指定拦截器类的全限定名--><bean class="com.jn.utils.MyInterceptor"></bean></mvc:interceptor></mvc:interceptors>
(五)、多个拦截器的执行顺序
1、多个拦截器放行的情况:
拦截器1:
package com.jn.utils;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyFirstInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("控制层执行之前的拦截器1");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("控制层执行器方法返回时拦截器1");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("控制层结束之后的拦截器1");}
}
拦截器2:
package com.jn.utils;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MySecondInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("控制层执行之前的拦截器2");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("控制层执行器方法返回时拦截器2");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("控制层结束之后的拦截器2");}
}
2、配置拦截器
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.jn.utils.MyFirstInterceptor"></bean></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.jn.utils.MySecondInterceptor"></bean></mvc:interceptor></mvc:interceptors>
3、多个拦截器阻断的情况:
第一个拦截器放回true,第二个拦截器返回true时
第一个拦截器放回true,第二个拦截器返回false时
第一个拦截器放回false,第二个拦截器返回true时
八、拦截器的简单案例(验证用户是否登录)
(一)实现思路分析
1、定义登录页面,并定义请求映射。
2、判断用户名密码是否正确
3、如果正确 向 session 中写入用户信息
4、返回登录成功。
5、拦截用户请求,判断用户是否登录
6、如果用户已经登录。放行
7、如果用户未登录,跳转到登录页面
(二)案例代码
1、登录页面login.jsp定义
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录页面</title><style>* {margin: 0;padding: 0;}html {height: 100%;}body {height: 100%;}.container {height: 100%;background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);}.login-wrapper {background-color: #fff;width: 358px;height: 588px;border-radius: 15px;padding: 0 50px;position: relative;left: 50%;top: 50%;transform: translate(-50%, -50%);}.header {font-size: 38px;font-weight: bold;text-align: center;line-height: 200px;}.input-item {display: block;width: 100%;margin-bottom: 20px;border: 0;padding: 10px;border-bottom: 1px solid rgb(128, 125, 125);font-size: 15px;outline: none;}.input-item:placeholder {text-transform: uppercase;}.btn {text-align: center;padding: 10px;width: 100%;margin-top: 40px;background-image: linear-gradient(to right, #a6c1ee, #fbc2eb);color: #fff;}.msg {text-align: center;line-height: 88px;}a {text-decoration-line: none;color: #abc1ee;}</style>
</head>
<body>
<div class="container"><div class="login-wrapper"><div class="header">Login</div><form action="login" method="post"><div class="form-wrapper"><input type="text" name="username" placeholder="username" class="input-item"><input type="password" name="password" placeholder="password" class="input-item"><input type="submit" value="Login" class="btn"> <!-- 将原来的div.btn改为input提交按钮 --></div><div class="msg">Don't have account?<a href="#">Sign up</a></div></form></div>
</div>
</body>
</html>
2、控制器实现
//测试拦截实现登录@RequestMapping("login")public String login(String username,String password,HttpSession session){System.out.println("登录校验成功");session.setAttribute("username",username);return "successful";}
3、拦截器实现
package com.jn.utils;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 {/*控制层执行之前的拦截器。改方法在控制层执行器方法前调用,该方法返回结果为true则继续调用下一个拦截器。改方法返回结果为false则不会调用下一个拦截器,也不会调用控制层执行器方法。*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("控制层执行之前的拦截器");//校验用户是否登录HttpSession session = request.getSession();String username = (String) session.getAttribute("username");if (username == null){return true;}else {//当前用户未登录,拦截跳转到登录页面request.getRequestDispatcher("/login.jsp").forward(request,response);return false;}}/*控制层执行器方法返回时拦截器该方法在控制层执行器方法返回时调用,由DispatcherServlet在将结果响应给浏览器前的调用。*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("控制层执行器方法返回时拦截器");}/*控制层结束之后的拦截器该方法在DispatcherServlet将结果响应给浏览器后调用。*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("控制层结束之后的拦截器");}
}
4、注册拦截器
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><mvc:exclude-mapping path="login"/><bean class="com.jn.utils.MyInterceptor"></bean></mvc:interceptor></mvc:interceptors>
5、测试结果
此时输入用户名,然后点击login
然后username不填,点击登录
然后还是跳转到了登录界面