SpringMVC 笔记【下】

16 篇文章 0 订阅

文章主要内容:

  1. 数据格式转化与格式化
  2. Hibernate Validator数据校验
  3. 拦截器
  4. Json数据处理

二、SpringMVC常用技术

本节示例项目的准备与第一节大致一致:

  1. 导包:

在这里插入图片描述

  1. 添加全局配置文件:

其中依赖包括:bean context mvc

<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">

	<context:component-scan base-package="com.cyt.springmvc"></context:component-scan>
	
	<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/view/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<mvc:default-servlet-handler/>
	<mvc:annotation-driven></mvc:annotation-driven>
</beans>
  1. 配置web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>springmvc2</display-name>
  
  <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
</web-app>

其中注意<param-value>classpath:springmvc.xml</param-value><url-pattern>/</url-pattern>

1 数据格式转化与格式化

1.1 Converter
  • Spring MVC框架的Converter<S, T>是一个可以将一种数据类型转换成另一种数据类型的接口,这里S表示源类型,T表示目标类型。

  • 开发者在实际应用中,使用框架内置的类型转换器基本就够了,但有时需要编写具有特定功能的类型转换器。

示例:将页面表单上输入的字符串转化为对象,例如将格式为字符串”name;price;amount”转换为一个Product对象

  1. 设计javabean

Product.java

public class Product {
	private String name;
	private Double price;
	private Integer amount;
  1. controller:

ProductController.java

@Controller
public class ProductController {

	
	@PostMapping("/addProduct")
	public String addProduct(@RequestParam("product")Product product) {
		System.out.println(product);
		return "success";
	}
}
  1. product.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<h1>Add Product</h1>
	<form action="addProduct" method="post">
		Product: <input type="text" name="product"/><br><br>
		<input type="submit" value="Submit">
	</form>
</body>
</html>
  1. 创建一个转换器 converter
public class StringProductConverter implements Converter<String, Product> {

	@Override
	public Product convert(String source) {
		if (source!=null) {
			String[] values = source.split(";");
			if (values!=null && values.length==3) {
				String name = values[0];
				Double price = Double.parseDouble(values[1]);
				Integer amount = Integer.parseInt(values[2]);
				Product product = new Product(name, price, amount);
				return product;
			}
		}
		return null;
	}	
}
  1. springmvc.xml

单单这样是不能进行自动转化的,要在全局配置文件中配置一个框架内的bean:

<bean id="formattingConversion" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="com.cyt.springmvc.converter.StringProductConverter"></bean>
        </list>
    </property>
</bean>
  1. success.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Success</title>
</head>
<body>
	<h1>Success</h1>
</body>
</html>
1.2 Formmater
  • Spring MVC框架的Formatter与Converter<S, T>一样,也是一个可以将一种数据类型转换成另一种数据类型的接口。但不同的是,Formatter的源数据类型必须是String类型,而Converter<S, T>的源数据类型是任意数据类型。

  • 在Web应用中,由HTTP发送的请求数据到控制器中都是以String类型获取。因此,在Web应用中选择Formatter比选择Converter<S, T>更加合理。

示例:日期数据格式化,例如将格式为”yyyy-MM-dd”日期格式化为Date类型

这里的string pattern规则是: " yyyy-MM-dd HH:mm:ss " 注意区分大写小,MM指月份,mm指分钟,HH是24小

时制,而hh是12小时制。

  1. product.jsp
<h1>add Date</h1>
<form action="addDate" method="post">
    Date: <input type="text" name="date"/><br><br>
    <input type="submit" value="Submit">
</form>
  1. controller:
@PostMapping("/addDate")
public String addDate(Date date) {
    System.out.println(date);
    return "success";
}
  1. success.jsp 与上小节无区别
  2. 创建一个Formatter:MyDateFormatter.java
public class MyDateFormatter implements Formatter<Date> {

	@Override
	public String print(Date date, Locale locale) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		if (date!=null) {
			return format.format(date);
		}
		else
			return null;
	}

	@Override
	public Date parse(String time, Locale locale) throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		if (time!=null) {
			return format.parse(time);
		}
		else
			return null;
	}
}
  1. 配置全局配置文件

springmvc.xml

<bean id="formattingConversion" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <!-- converters 为上一节留下来的 -->
    <property name="converters 为上一节留下来的 -->">
        <list>
            <bean class="com.cyt.springmvc.converter.StringProductConverter"></bean>
        </list>
    </property>
    <property name="formatters">
        <list>
            <bean class="com.cyt.springmvc.converter.MyDateFormatter"></bean>
        </list>
    </property>
</bean>

2 Hibernate Validator数据校验

数据验证分为客户端验证和服务器端验证,客户端验证主要是过滤正常用户的误操作,主要通过JavaScript代码完成;服务器端验证是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现。

2.1 空检查

@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.

2.2 Booelan检查

@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false

2.3 长度检查

@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.

2.4 日期检查

@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。

2.5 邮件地址

@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。

2.6 数值检查

@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 被指定的元素必须在合适的范围内

2.7 示例
  1. 先导入Hibernate Validator所需jar包:

在这里插入图片描述

common-logging为之前导入,也是必需

  1. 新建一个bean,并在属性上注解:

Staff.java:

public class Staff {
	@NotEmpty(message = "{staff.name.required}")
	private String name;
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	@Past(message = "{staff.birth.past}")
	private Date birth;
	@NumberFormat(pattern = "$#,###,###.##")
	private Double salary;
	@NumberFormat(pattern = "#,###,###")
	private Integer sells;
	@Email(message = "{staff.email.format}")
	@NotEmpty(message = "{staff.email.required}")
	private String email;
	@NotEmpty(message = "{staff.password.required}")
	@Length(min = 6,max = 12,message = "{staff.password.length}")
	private String password;
  1. 定义错误消息资源文件

errorMessages.properties:

staff.name.required=name can't be empty
staff.birth.past=birth can't be a past time
staff.email.format=email is illegal
staff.email.required=email can't be empty
staff.password.required=password can't be empty
staff.password.length=password's length should between 6 and 12
typeMismatch.staff.birth=the block need a date
  1. 使用@Valid注解进行数据验证

controller:

@Controller
public class StaffController {

	@GetMapping("/inputStaff")
	public String inputStaff(Model model) {
		model.addAttribute("staff",new Staff());
		return "inputStaff";
	}
	
	@PostMapping("addStaff")
	public String addStaff(@Valid Staff staff, BindingResult result) throws UnsupportedEncodingException {
		if (result.hasErrors()) {
			return "inputStaff";
		}else {
			System.out.println(staff);
			return "success";			
		}
	}
	
}

在形参 Staff staff 前加上@Valid:@Valid Staff staff

  1. 在jsp页面上显示错误消息
<body>
	<h1>input Staff Info</h1>
	<form:form modelAttribute="staff" action="addStaff" method="post">
		Name: <form:input path="name"/><form:errors path="name"></form:errors><br><br>
		Birth: <form:input path="birth"/><form:errors path="birth"></form:errors><br><br>
		Salary: <form:input path="salary"/><form:errors path="salary"></form:errors><br><br>
		Sells: <form:input path="sells"/><form:errors path="sells"></form:errors><br><br>
		Email: <form:input path="email"/><form:errors path="email"></form:errors><br><br>
		Password: <form:password path="password"/><form:errors path="password"></form:errors><br><br>
		<input type="submit" value="Submit">
	</form:form>
</body>

使用<form:errors path=""> 进行显示错误消息

以上 modelAttribute="staff" 是 taglib中的form标签规定需要先准备模型数据,故,

上面controller第6行代码 model.addAttribute("staff",new Staff()); 为taglib中的form标签提供模型数据

  1. 配置全局配置文件

springmvc.xml:

<!-- 配置hibernate-validator所需资源文件,在这里是错误消息文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>/WEB-INF/prop/errorMessages</value>
        </list>
    </property>
    <property name="fileEncodings" value="utf-8"></property>
    <property name="cacheSeconds" value="60"></property>
</bean>
<!-- 注册校验器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
    <property name="validationMessageSource" ref="messageSource"></property>
</bean>

<mvc:default-servlet-handler/>
<mvc:annotation-driven conversion-service="formattingConversion" validator="validator">
</mvc:annotation-driven>

注意:记得在mvc:annotation-driven中加入 validator="validator"

3 拦截器

3.1 创建 HandlerInterceptor 并测试
  1. FirstInterceptor.java:
package com.cyt.springmvc.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class FirstInterceptor implements HandlerInterceptor {

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("FirstInterceptor ======> preHandle");
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("FirstInterceptor ======> postHandle");
	
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("FirstInterceptor ======> afterCompletion");
		
	}
}

实现 HandlerInterceptor 接口 并实现三个接口方法

  • preHandle()方法:该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作。返回true表示继续向下执行,返回false表示中断后续操作。

  • postHandle()方法:该方法在控制器的处理请求方法调用之后,解析视图之前执行。可以通过此方法对请求域中的模型和视图做进一步的修改。

  • afterCompletion()方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行。可以通过此方法实现一些资源清理等工作。

  1. 全局配置文件

springmvc.xml 配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**/*"/>
        <bean class="com.cyt.springmvc.interceptor.FirstInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>
  1. controller:

InterceptorController.java

@Controller
public class InterceptorController {

	@GetMapping("/interceptor")
	public String interceptor() {
		System.out.println("do business logic......");
		return "success";
	}
}
  1. jsp:
<a href="interceptor">Go to interceptorController</a>

控制台输出:

FirstInterceptor ======> preHandle
do business logic......
FirstInterceptor ======> postHandle
FirstInterceptor ======> afterCompletion
  1. 可以在postHandle()方法中对视图做修改:

例如:

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                       ModelAndView modelAndView) throws Exception {
    modelAndView.setViewName("inputStaff");
    modelAndView.addObject("staff",new Staff());
    System.out.println("FirstInterceptor ======> postHandle");

}
  1. 其中modelAndView.addObject("staff",new Staff());是因为inputStaff试图中设置了ModelAttribute提前准备数据。

  2. modelAndView.setViewName("inputStaff");设置之后,拦截器会把请求转发到inputStaff。

3.2 拦截其他文件

由于我们在全局配置文件中配置了:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**/*"/>
        <bean class="com.cyt.springmvc.interceptor.FirstInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

<mvc:mapping path="/**/*"/>可以拦截所有资源,包括静态资源等

  1. 静态资源拦截:

在Webcontent下创建相应目录和文件,然后访问:

http://localhost:8080/springmvc2/txt/a.txt

拦截器一样可以起效

  1. 拦截器排除
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**/*"/>
        <mvc:exclude-mapping path="/txt/a.txt"/>
        <bean class="com.cyt.springmvc.interceptor.FirstInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

<mvc:exclude-mapping path="/txt/a.txt"/>不拦截/txt/a.txt

<mvc:exclude-mapping path="/txt/*.txt"/>不拦截txt下所有txt文件

3.2 多个拦截器

配置两个拦截器,SecondInterceptor 在FirstInterceptor 之后配置

SecondInterceptor .java

package com.cyt.springmvc.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class SecondInterceptor implements HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("SecondInterceptor ======> preHandle");
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("SecondInterceptor ======> postHandle");
	
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("SecondInterceptor ======> afterCompletion");
		
	}
}

全局配置文件

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**/*"/>
        <mvc:exclude-mapping path="/txt/a.txt"/>
        <bean class="com.cyt.springmvc.interceptor.FirstInterceptor"></bean>
    </mvc:interceptor>
    <bean class="com.cyt.springmvc.interceptor.SecondInterceptor"></bean>
</mvc:interceptors>

效果:(控制台打印)

FirstInterceptor ======> preHandle
SecondInterceptor ======> preHandle
do business logic......
SecondInterceptor ======> postHandle
FirstInterceptor ======> postHandle
SecondInterceptor ======> afterCompletion
FirstInterceptor ======> afterCompletion
  1. 注意拦截器注册的先后顺序,以及拦截器三个方法起效的先后顺序
  2. 注意!!!!在配置文件注册拦截器时,可以直接用<bean>标签,就默认全部拦截,不设任何mapping,例如这个例子中的<bean class="com.cyt.springmvc.interceptor.SecondInterceptor"></bean>

4 Json数据处理

导入jar包:

在这里插入图片描述

4.1 向页面发送json数据

index.jsp

<a href="getJson">Get Json Data</a>

javabean:Product.java

public class Product {
	private String name;
	private Double price;
	private Integer amount;
	private Date produceTime;
    
    public Product(String name, Double price, Integer amount) {
		super();
		this.name = name;
		this.price = price;
		this.amount = amount;
		this.produceTime = new Date();
	}

controller:

JsonController.java

@Controller
public class JsonController {

	@ResponseBody
	@GetMapping("/getJson")
	public Product getJson() {
		 Product product = new Product("shoes", 100.5, 3);
		 return product;
	}
}

用Chrome打开网址http://localhost:8080/springmvc2/index.jsp点击链接可以看到:

{"name":"shoes","price":100.5,"amount":3,"produceTime":1604572798092}
4.2 接收页面发送的数据
  1. controller:
@ResponseBody
@GetMapping("/json")
public Product json(@RequestBody Product product) {
    System.out.println(product);
    Product result = new Product("clothes", 50.6, 3);
    return result;
}

这里返回值没有实际用处

  1. 用Postman 软件给链接: http://localhost:8080/springmvc2/json 发送数据

在这里插入图片描述

控制台把接收到的数据封装成类并打印

FirstInterceptor ======> preHandle
SecondInterceptor ======> preHandle
Product [name=shoes, price=100.5, amount=3, produceTime=Wed Nov 04 18:45:37 CST 2020]
SecondInterceptor ======> postHandle
FirstInterceptor ======> postHandle
SecondInterceptor ======> afterCompletion
FirstInterceptor ======> afterCompletion
4.3 在接收数据时做数据校验

这里用Product的name属性做示例

  1. 在封装类中做注解:
public class Product {
	@NotEmpty(message = "{product.name.required}")
	private String name;
	private Double price;
	private Integer amount;
	private Date produceTime;
  1. 在errorMessages.properties中添加:
product.name.required=the product name can't be empty
  1. controller:
@ResponseBody
@GetMapping("/json")
public Product json(@RequestBody @Valid Product product,BindingResult result) {
	if (result.hasErrors()) {
		System.out.println(result.getFieldError("name").getDefaultMessage());
	} else {
		System.out.println(product);
	}
	
	// 下面代码只是为了返回值而设定
	Product prod = new Product("clothes", 50.6, 3);
	return prod;
}	
  1. 用Postman发送json数据:
{"name":"","price":100.5,"amount":3,"produceTime":1604486737127}

控制台输出:

FirstInterceptor ======> preHandle
SecondInterceptor ======> preHandle
the product name can't be empty
SecondInterceptor ======> postHandle
FirstInterceptor ======> postHandle
SecondInterceptor ======> afterCompletion
FirstInterceptor ======> afterCompletion

====== SpringMVC 끝나다 !======

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值