SpringMVC学习笔记(二)
五、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不填,点击登录
然后还是跳转到了登录界面
相关文章:
SpringMVC学习笔记(二)
五、Rest风格编程 (一)Rest风格URL规范介绍 1、什么是restful RESTful架构,就是目前最流行的一种互联网软件架构风格。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。REST这个词,是Roy T…...
51c嵌入式~单片机合集2
我自己的原文哦~ https://blog.51cto.com/whaosoft/12362395 一、不同的电平信号的MCU怎么通信? 下面这个“电平转换”电路,理解后令人心情愉快。电路设计其实也可以很有趣。 先说一说这个电路的用途:当两个MCU在不同的工作电压下工作&…...
JavaScript:浏览器对象模型BOM
BOM介绍 浏览器对象模型(Brower Object Model,BOM)提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window BOM由一系列相关的对象构成,并且每个对象都提供了很多方法和属性。 BOM与DOM区别 DOM是文档对…...
Unity音频导入设置
参考:unity官方文档 导入设置 Force To Mono:强制单声道。启用后音频片段将降混为单声道声音。可以节省该资源所占据的空间。 Normalize:峰值归一化。降混过程通常会导致信号比原始信号更安静。峰值归一化的信号为音频源的音量属性提供了后…...
【数据分享】中国对外投资合作发展报告(2013-2023)
数据介绍 绪 论............................................................................................................................. 1 对外投资合作高质量发展迈出新步伐................................................................... 2 第一篇 发…...
java8之Stream流
文章目录 Stream流的定义和特性定义特性中间操作终结操作 生成流forEachmapfilterlimitsorted并行(parallel)程序Collectors Stream流的定义和特性 定义 Stream是Java 8 API添加的一个新的抽象,用于以声明性方式处理数据集合。它…...
pipx安装提示找不到包
执行: pipx install --include-deps --force "ansible6.*"WARNING: Retrying (Retry(total4, connectNone, readNone, redirectNone, statusNone)) after connection broken by NewConnectionError(<pip._vendor.urllib3.connection.HTTPSConnection …...
Codeforces Round 987 (Div. 2)(前四道)
A. Penchick and Modern Monument 翻译: 在繁华大都市马尼拉的摩天大楼中,菲律宾最新的 Noiph 购物中心刚刚竣工!建筑管理方 Penchick 订购了一座由 n 根支柱组成的先进纪念碑。 纪念碑支柱的高度可以用一个由 n 个正整数组成的数组 h 来表示…...
PCB+SMT线上报价系统+PCB生产ERP系统自动化拼板模块升级
PCB生产ERP系统的智能拼版技术,是基于PCB前端报价系统获取到的用户或市场人员已录入系统的板子尺寸及set参数等,按照最优原则或利用率最大化原则自动进行计算并输出拼版样式图和板材利用率,提高工程人员效率,减少板材的浪费。覆铜…...
微信小程序_小程序视图与逻辑_day3
一、目标 A. 能够知道如何实现页面之间的导航跳转 B. 能够知道如何实现下拉刷新效果 C. 能够知道如何实现上拉加载更多效果 D. 能够知道小程序中常用的生命周期 二、目录 A. 页面导航 B. 页面事件 C. 生命周期 D. WXS脚本 E. 案例-本地生活(列表页面)…...
kubesphere环境-本地Harbor仓库+k8s集群(单master 多master)+Prometheus监控平台部署
前言:半月前在公司生产环境上离线部署了k8s集群Victoria Metrics(二开版)自研版夜莺 监控平台的搭建,下面我租用3台华为云服务器演示部署kubesphere环境-本地Harbor仓库k8s集群(单master节点 & 单master节点)Prometheus监控部…...
【提高篇】3.3 GPIO(三,工作模式详解 上)
目录 一,工作模式介绍 二,输入浮空 2.1 输入浮空简介 2.2 输入浮空特点 2.3 按键检测示例 2.4 高阻态 三,输入上拉 3.1 输入上拉简介 3.2 输入上拉的特点 3.3 按键检测示例 四,输入下拉 4.1 输入下拉简介 4.2 输入下拉特点 4.3 按键检测示例 一,工作模式介绍…...
‘视’不可挡:OAK相机助力无人机智控飞行!
南京邮电大学通达学院的刘同学用我们的oak-d-lite实现精确打击无人机的避障和目标识别定位功能,取得了比赛冠军。我们盼望着更多的朋友们能够加入到我们OAK的队伍中来,参与到各式各样的比赛中去。我们相信,有了我们相机的助力,大家…...
javaScript交互补充(元素的三大系列)
1、元素的三大系列 1.1、offset系列 1.1.1、offset初相识 使用offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等 获得元素距离带有定位祖先元素的位置获得元素自身的大小(宽度高度)注意:返回的数值都不…...
数据结构(基本概念及顺序表)
基本概念: 1、引入 程序数据结构算法 数据: 数值数据:能够直接参加运算的数据(数值,字符) 非数值数据:不能够直接参加运算的数据(字符串、图片等) 数据即是信息的载…...
【全面系统性介绍】虚拟机VM中CentOS 7 安装和网络配置指南
一、CentOS 7下载源 华为源:https://mirrors.huaweicloud.com/centos/7/isos/x86_64/ 阿里云源:centos-vault-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云 百度网盘源:https://pan.baidu.com/s/1MjFPWS2P2pIRMLA2ioDlVg?pwdfudi &…...
html + css 自适应首页布局案例
文章目录 前言一、组成二、代码1. css 样式2. body 内容3.全部整体 三、效果 前言 一个自适应的html布局 一、组成 整体居中,宽度1200px,小屏幕宽度100% 二、代码 1. css 样式 代码如下(示例): <style>* {…...
时钟之CSS+JS版
写在前面 此版本绘制的时钟基于CSSJS模式。 优点操作简单,缺点当然是不够灵活。下一篇会基于HTML5的canvas标签,使用JS绘制。会更灵活,元素更加丰富。 HTML代码 <div class"box"><article class"clock"><…...
ubuntu18.04 配置安卓编译环境
目前有个项目,验收时有个要求是在linux中进行编译打包生成apk文件。我平时都是在windows环境android studio中进行打包的,花了半天时间研究了一下,记录如下: 安装安卓sdk cd /opt wget https://dl.google.com/android/reposito…...
pycharm分支提交操作
一、Pycharm拉取Git远程仓库代码 1、点击VCS > Get from Version Control 2、输入git的url,选择自己的项目路径 3、点击Clone,就拉取成功了 默认签出分支为main 选择develop签出即可进行开发工作 二、创建分支(非必要可以不使用…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

