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不填,点击登录

 然后还是跳转到了登录界面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/471226.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch深度学习与企业级项目实战-预训练语言模型GPT

【图书推荐】《PyTorch深度学习与企业级项目实战》-CSDN博客 13个PyTorch深度学习案例简介-CSDN博客 《PyTorch深度学习与企业级项目实战&#xff08;人工智能技术丛书&#xff09;》(宋立桓&#xff0c;宋立林)【摘要 书评 试读】- 京东图书 (jd.com) PyTorch深度学习算法与…

CTF攻防世界小白刷题自学笔记13

1.fileinclude,难度&#xff1a;1,方向&#xff1a;Web 题目来源:宜兴网信办 题目描述:无 给一下题目链接&#xff1a;攻防世界Web方向新手模式第16题。 打开一看给了很多提示&#xff0c;什么language在index.php的第九行&#xff0c;flag在flag.php中&#xff0c;但事情显…

【QT常用技术讲解】优化网络链接不上导致qt、qml界面卡顿的问题

前言 qt、qml项目经常会涉及访问MySQL数据库、网络服务器&#xff0c;并且界面打开时的初始化过程就会涉及到链接Mysql、网络服务器获取数据&#xff0c;如果网络不通&#xff0c;卡个几十秒&#xff0c;会让用户觉得非常的不爽&#xff0c;本文从技术调研的角度讲解解决此类问…

基于OpenCV的自制Python访客识别程序

这是我用Pyqt5&#xff0c;基于OpenCV做的一个Python访客识别程序&#xff0c;它具体包括如下5个功能&#xff1a; 1、选择媒体菜单&#xff0c;可以打开本地摄像头&#xff1b;如果知道rtsp地址&#xff0c;则可以直接访问局域网内的网络串流。 2、选择播放菜单&#xff0c;…

SQL集合运算

集合论是SQL语言的根基。 1 集合运算 注意事项&#xff1a; 1&#xff09;SQL能操作具有重复行的集合&#xff0c;可以通过可选项ALL来支持。 如果直接使用UNION或INTERSECT&#xff0c;结果里不会出现重复的行。如果想在结果里留下重复行&#xff0c;可以加上可选项ALL。写…

Gartner发布安全平台创新洞察:安全平台需具备的11项常见服务

安全和风险管理领导者的任务是管理多个安全供应商和复杂的基础设施堆栈。本研究提供了有关安全平台优势和风险的见解&#xff0c;并提供了为组织选择合适平台的建议。 主要发现 自适应和行为安全防御需要跨安全基础设施组件进行更多的协调&#xff0c;而目前孤立的异构供应商架…

基于海思soc的智能产品开发(两个图像处理来源)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于图像&#xff0c;大家能够想到的一般就是sensor&#xff0c;也就是摄像头。其实对于图像来说&#xff0c;还有另外一个来源&#xff0c;那就是…

如何使用 Web Scraper API 高效采集 Facebook 用户帖子信息

目录 前言一、什么是Web Scraper API二、Web Scraper API 的优势&#xff1a;三、Web Scraper API 适用场景四、实践案例目标需求视频讲解1、选择Web Scraper API2、登录注册3、进入用户控制面板4、选择API5、触发数据收集 API6、获取爬虫结果7、分析爬虫结果&#xff08;1&…

微信小程序中使用离线版阿里云矢量图标

前言 阿里矢量图库提供的在线链接服务仅供平台体验和调试使用&#xff0c;平台不承诺服务的稳定性&#xff0c;企业客户需下载字体包自行发布使用并做好备份。 1.下载图标 将阿里矢量图库的图标先下载下来 解压如下 2.转换格式 贴一个地址用于转换格式&#xff1a;Onlin…

Ubuntu 的 ROS 操作系统安装与测试

引言 机器人操作系统&#xff08;ROS, Robot Operating System&#xff09;是一个用于开发机器人应用的开源框架&#xff0c;它提供了一系列功能丰富的库和工具&#xff0c;能够帮助开发者构建和控制机器人。 当前&#xff0c;ROS1的最新版本为Noetic Ninjemys&#xff0c;专为…

封装一个省市区的筛选组件

筛选功能&#xff1a;只能单选&#xff08;如需多选需要添加show-checkbox多选框属性&#xff09;&#xff0c;选中省传递省的ID&#xff0c;选中市传递省、市的ID&#xff0c; 选中区传递省市区的ID 父组件&#xff1a; <el-form-item><div style"width: 240px;…

python制作一个简单的端口扫描器,用于检测目标主机上指定端口的开放状态

import argparse # 用于解析命令行参数 from socket import * # 导入 socket 库的所有内容&#xff0c;用于网络通信 from threading import * # 导入 threading 库的所有内容&#xff0c;用于多线程操作 # 创建一个信号量&#xff0c;初始值为 1&#xff0c;用于线程同步&…

OceanStor Pacific系列 8.1.0 功能架构

功能架构 华为OceanStor Pacific系列提供基于三层的分布式存储架构&#xff0c;融合分布式文件、对象、大数据和块多个服务形态&#xff0c;支持文件、对象、大数据服务部署在一个集群&#xff0c;并统一管理。 华为OceanStor Pacific系列整体功能架构由存储接口层、存储服务…

Flink1.19编译并Standalone模式本地运行

1.首先下载源码 2.本地运行 新建local_conf和local_lib文件夹&#xff0c;并且将编译后的文件放入对应的目录 2.1 启动前参数配置 2.1.2 StandaloneSessionClusterEntrypoint启动参数修改 2.1.3 TaskManagerRunner启动参数修改 和StandaloneSessionClusterEntrypoint一样修改…

高效稳定!新加坡服务器托管方案助力企业全球化布局

在全球化的商业环境中&#xff0c;企业对于高效、稳定的服务器托管方案的需求日益迫切。作为亚洲的服务器托管中心&#xff0c;新加坡凭借其独特的地理位置、稳定的政治环境、先进的科技设施以及开放的市场政策&#xff0c;为企业提供了理想的服务器托管解决方案&#xff0c;助…

JavaWeb后端开发知识储备1

目录 1.DTO/VO/PO 2.MVC架构/微服务架构 3.JWT令牌流程 4.ThreadLocal 5.接口路径/路径参数 1.DTO/VO/PO 1.1 DTO DTO 即 Data Transfer Object—— 数据传输对象&#xff0c;是用于传输数据的对象&#xff0c;通常在服务层与表现层之间传递数据&#xff0c;DTO 通常用于…

StructuredStreaming (一)

一、sparkStreaming的不足 1.基于微批,延迟高不能做到真正的实时 2.DStream基于RDD,不直接支持SQL 3.流批处理的API应用层不统一,(流用的DStream-底层是RDD,批用的DF/DS/RDD) 4.不支持EventTime事件时间&#xff08;一般流处理都会有两个时间&#xff1a;事件发生的事件&am…

信号-3-信号处理

main 信号捕捉的操作 sigaction struct sigaction OS不允许信号处理方法进行嵌套&#xff1a;某一个信号正在被处理时&#xff0c;OS会自动block改信号&#xff0c;之后会自动恢复 同理&#xff0c;sigaction.sa_mask 为捕捉指定信号后临时屏蔽的表 pending什么时候清零&…

软件工程师简历(精选篇)

【#软件工程师简历#】 一份专业而精准的软件工程师简历&#xff0c;不仅能够全面展示技术实力和项目经验&#xff0c;更是赢得理想工作机会的重要敲门砖。那么&#xff0c;如何撰写一份令人印象深刻的软件工程师简历呢&#xff1f;以下是幻主简历整理的软件工程师简历&#xf…

基于springboot的汽车租赁管理系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…