SSM框架学习(三)————SpringMVC


一.MVC模式

mvc模式这里不作讲述,请参考:SSM框架学习(一)——SSM框架简介


二.Sring Web MVC简介及工作流程

2.1 Spring Web MVC简介

Spring Web MVC是Spring框架一个非常重要的模块之一,其采用了MVC架构模式的思想,将web层进行职责解耦,便于我们简单、快速开发出MVC结构的Web程序,并且它的API还封装了Web开发中的一些常见功能,简化了web程序开发的过程。

Spring Web MVC核心组件:

  • DispatcherServlet(控制器,请求派发)
  • HandlerMapping(处理器映射器,请求派发)
  • Controller(处理器,请求处理流程)
  • ModelAndView(模型,封装业务处理结果和视图)
  • ViewResolver(视图,视图显示处理器)

2.2Spring Web MVC工作流程

Spring Web MVC工作流程图

1.用户发起请求到DispatcherServlet(前端控制器),该控制器会过滤出那些请求可以访问Servlet、哪些不能访问。就是url-pattern的作用,并且会加springmvc.xml配置文件。
2.前端控制器会找到HandlerMapping(处理器映射器),通过处理器映射器完成url到controller映射组件,简单来说就是将在springmvc.xml中配置的或则注解的url与对应的处理器类找到并进行存储,用map<url,handler>存储。
3.HandlerMapping有了映射关系,并且找到url对应的处理器,HandlerMapping就会将处理器(Hnadler)返回,在返回前,会加上很多拦截器。
4.DispatcherServlet拿到Handler后,找到HandlerAdapter(处理器适配器),通过它来访问处理器,并执行处理器。
5.执行处理器(一般是指Controller)
6.处理器会返回一个ModelAndView对象给HandlerAdapter。
7.通过HandlerAdapter将ModelAndView对象返回给前端控制器(DispatcherServlet)。
8.前端控制器请求ViewResolver(视图解析器)进行视图解析,,根据逻辑视图名解析成真正的视图(jsp),其实就是将ModelAndView对象中存放视图的民初进行查找,找到对应的页面形成视图对象。
9.返回视图对象到前端控制器,此时ModelAndView对象中既有数据又有视图。
10.视图渲染,就是将ModelAndView对象中的数据放到request域中,用来让页面加载数据的。
11.通过第八步,通过名称找到了对应的页面,通过第十步request域中有了所需要的数据,那么就能够进行视图渲染了,最后将其返回即可。


三.搭建Spring Web MVC工作环境

  1. 导入jar包
  • commons-logging.jar
  • spring-beans-5.1.3.RELEASE.jar
  • spring-context-5.1.3.RELEASE.jar
  • spring-core-5.1.3.RELEASE.jar
  • spring-expression-5.1.3.RELEASE.jar

除此之外还要导入

  • spring-aop-5.1.3.RELEASE.jar

百度网盘下载地址:点击下载
git下载地址:点击下载

  1. 配置InternalResourceViewResource(视图解析器)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--配置视图解析器的前缀和后缀,后缀为文件类型名-->
        <property name="prefix" value="/jsp/"/>
        <property name="suffix" value=".jsp"/>
     </bean>
</beans>

InternalResourceViewResolver视图解析器用于应用的内部内部资源的封装与跳转。而对于内部查找规则是将逻辑视图名称配置为前缀(prefix)与后缀(suffix)的方式,即前缀 + 视图名称 + 后缀。

  1. 再web.xml中配置前端控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--配置前端控制器-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/SpringMVC.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

load-on-startup:
1.load-on-startup元素标记容器是否应该在web应用程序启动的时候就加载这个servlet,(实例化并调用init()方法)
2.它必须是一个整数,表示servlet被加载的先后顺序
3.如果该元素的值为负数或则没有设置,则容器会当Servlet被请求时再加载。
4.如果值为正数或则0时,表示容器在应用启动时就夹在并初始化这个servlet,值越小,servlet的优先级就越高,就越先被加载,值相同时,容器就会现在自己顺序加载

  1. 创建jsp文件夹,并在jsp文件夹里面创建hello.jsp,hello.jsp内容随便写。
  2. 写个处理器类(Controller类,其负责执行具体业务逻辑处理,可以调用Service,DAO等组件,编程时需要实现Controller接口和约定的方法)
package controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

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

/**
 * @author zqq
 * @create 2019-08-04-19:07
 */
public class HelloController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        System.out.println("控制开始执行");
        return new ModelAndView("hello");
    }
}

ModelAndView组件简介:
controller组件在实现约定的HandlerRequest方法处理完成业务逻辑之后,需要返回一个ModelAndView对象,其主要作用是将后台处理完的数据封装在ModelAndView中,最后将这些数据传递给view层,且同时包含一个展示该数据的视图(jsp)的url地址
常见构造器有:

  1. ModelAndView(String viewName):
    viewName: 视图名,即要显示的jsp的名字,视图解析器ViewResolver在解析ModelAndView对象时,通过该名字找到对应的jsp
  2. ModelAndView(String viewName,Map model)
    model: 处理好的结果数据,多个数据按key-value存放,方便在视图中将这些数据一一取出。
  1. 配置applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="helloController" class="controller.HelloController"/>
    <!--配置处理器映射器,通过该组件,可以将用户对应请求映射到指定的controller组件上-->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <!--key是访问路径,value就是要访问controller的bean的id-->
                <prop key="hello.do">helloController</prop>
            </props>
        </property>
    </bean>
</beans>

测试成功与否:

在浏览器输入:http://localhost:8080/FirstWeb/hello.do
看是否出现你在hello.jsp里面写的内容


四.基于注解的spring开发

  1. @Controller注解

普通实现controller类的方法是继承特定父类或实现特定接口,但是如果使用@Controller注解来声名@Controller注解,可以使得控制器类可以不用继承特定类和实现特定接口,而使用controller接口需要实现指定方法,这样会导致该控制器类只能处理一个单一的请求动作,而使用@Controller注解声名的类可以支持同时多个请求动作,更加灵活。

  1. @RequestMapping注解

@RequestMapping注解既可以作用在类上面,也可以作用在方法上,该注解标明这个类或者这个方法与客户的某一个请求相对应。使用了该注解就不需要去逐个配置HandlerMapping和Handler。

  • Spring分发处理器会扫描使用了Controller注解类的方法,并检查该方法是否使用了@RequestMapping注解,而使用了@RequestMapping注解的方法才是真正处理请求的处理器,所以一般会让这两个注解联合使用。
    导入jar包:
  • spring-web-5.1.3.RELEASE.jar
  • spring-webmvc-5.1.3.RELEASE.jar

配置springmvc.xml

<!--扫描注解-->
<context:component-scan base-package="controller"/>
<!--扫描RequestMapping注解-->
<mvc:annotation-driven/>

修改HelloController文件如下:

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author zqq
 * @create 2019-08-04-19:07
 */

@Controller
@RequestMapping("hello")
public class HelloController{
    @RequestMapping("data")
    public String data(){
            return "hello";
   }
}

检验成功与否:
访问地址:http://localhost:8080/FirstWeb/hello/data.do
查看是否出现hello.jsp文件的内容

五.页面值的接收与向页面传值

5.1 页面值的接收

  1. 使用HttpServletRequest获取
  2. 使用@RequestParam注解
  3. 使用自动封装机制封装Bean对象

修改hello.jsp文件内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Hello</h1>
	<a href="${pageContext.request.contextPath}/index/user.do">去首页</a>
	<a href="${pageContext.request.contextPath}/index/data.do?uname=Alice">测试参数传递</a>
	
	<form action="${pageContext.request.contextPath}/index/register.do" method="post">
		<div>
			用户名:<input name="userName" type="text">
		</div>
		<div>
			密码:<input name="password" type="password">
		</div>
		<div>
			年龄:<input name="age" type="text">
		</div>
		<div>
			电话号码:<input name="phoneNumber" type="text">
		</div>
		<input type="submit" value="提交"/>
	</form>
</body>
</html> 

新建index.jsp,内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>欢迎来到首页</h1>
	<h2>${message }</h2>
	<h2>${userName }</h2>
	<h2>${user.userNmae }----${user.password }</h2>
</body>
</html>

新建IndexController.java,内容如下:

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import cn.goktech.entity.User;

@Controller
@RequestMapping("/index")
public class IndexController {
	//String,ModelAndView,Model,Map,void,View
	@RequestMapping("/user")
	public String index(HttpServletRequest request){
		System.out.println("注解Controller访问成功");
		request.setAttribute("message", "注解访问Controller成功!");
		//request.getParameter(“userName”);使用这个方法获取前端传过来的数据
		return "index";
	}
	/*
	 * 传递数据:
	 * 1.request
	 * 2.@RequestParam("uname"):获取页面传递的指定参数的值
	 * 3.获取多个字段可以用类来接受,但form表单中name要跟类的字段一一对应
	 */
	@RequestMapping("/data")
	public String getData(@RequestParam("uname") String userName,Map<String, String> map) {
		System.out.println(userName);
		map.put("userName", userName);
		return "index";
	}
	@RequestMapping("/register")
	public String register(@ModelAttribute("user")  User user) {
		System.out.println(user.getUserName()+"----"+user.getPassword());
		return "index";
	}
}

5.2向页面传值

  1. 使用HttpRequestServlet和session
@RequestMapping(“login”)
public String  checkLogin(String userName ,String  pswd,HttpServletRequest  req){
	UserBean user=userService.login(userName ,password );
	req.setAttribute("loginMesg", "登录成功");
	req.getSession().setAttribute(“loginuser”,user);
	model.addAttribute(“user”,user);
	return “userCenter“;
}

在jsp页面使用EL表达式就可以获取值了 l o g i n M e s g , {loginMesg}, {user.userName}

  1. 使用Map向页面传值
public String test1(Map<String, String> map){
	/** 不需要map实例,Spring会帮我们创建
	* 效果和request.setAttribut() 相同,故在jsp可以通过${key1 }获得值
	*/
	map.put("key1", "value-1"); 
	map.put("key2", "value-2"); 
	return "userCenter";
}
  1. 使用Model和ModelMap向页面传值

在Controller处理方法中添加ModelMap或者Model参数,两个作用效果都一样,Model 是一个接口,继承了ModelMap类。ModelMap也是继承了Map的。

@RequestMapping(“login.do)
public String  checkLogin(ModelMap model ){
	UserBean user=userService.login(userName ,password );
	// Model 的用法在这里也一样的,并且在他两中里也没法设定要跳转的jsp地址
	model.addAttribute(“user”,user);
	return “seccess”
}
//ModelMap数据会利用HttpServletRequest 的Attribute传递至jsp页面中
  1. 使用ModelAndView向页面传值

对于控制器的目标方法,无论返回值是String、View、Map,Model还ModelMap,SpringMVC都会在内部将它们封装为一个ModelAndView对象进行返回给视图解析器。
ModelAndView类如其名称所示,代表了程序中Model与View的对象,只不过它能方便你一次返回这两个对象,Model与View两者仍是分离的概念,像ModelMap就只含模型。

@RequestMapping(“login.do)
public ModelAndView checkLogin(String userName ,String  password ){
	UserBean user=userService.login(userName ,password );
	Map<String Object> data=new HashMap<String Object>();
	data.put(“user”,user);
	return new ModelAndView(“seccess”,data);
}
  1. 使用@ModelAttribute传值
@Controller 
public class HelloWorldController { 
    @ModelAttribute("user") 
    public User addAccount() { 
        return new User("jz","123"); 
     } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld(@ModelAttribute("user") User user) { 
        user.setUserName("jizhou"); 
   		return "helloWorld"; 
    } 
}

@ModelAttribute(“user”) User user注释方法参数,参数user的值来源于addAccount()方法中的model属性。此时如果方法体没有标注@SessionAttributes(“user”),那么scope为request,如果标注了,那么scope为session。@ModelAttribute数据会利用HttpServletRequest的Attribute传递至jsp页面中。

  1. 使用@SessionAttribte传值

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import cn.goktech.entity.User;

@SessionAttributes(value= {"user"},types= {String.class})
@Controller
public class RegisterController {
	
//	@RequestMapping("/register")
//	public String register(Model model,User user) {
//		model.addAttribute("user", user);
//		return "userInfo";
//	}
	
	@RequestMapping("/register")
	public ModelAndView register(User user) {
		Map<String, Object> data = new HashMap<>();
		data.put("user", user);
		return new ModelAndView("userInfo", data);
	}
	
	
	@RequestMapping("/userInfo")
	public String register(@RequestParam("name") String name,@RequestParam("age") String age, @RequestParam("gender") String gender,Model model) {
		System.out.println("name--"+name);
		System.out.println("age--"+age);
		System.out.println("gender--"+gender);
		
		User user = new User();
		user.setName(name);
		user.setAge(age);
		user.setGender(gender);
		model.addAttribute("user", user);
		return "userInfo";
	}
	
}

注册之后user就保存在了session中,访问/userinfo就可以访问到了

六.过滤器

在提交表单如果遇到中文乱码,Spring提供了CharacterEncodingFilter过滤器解决乱码,在web.xml中进行设置过滤器

 <!--配置字符集过滤器-->
<filter>
	<filter-name>CEF</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>CEF</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

七.拦截器

拦截器在SpringMVC中有着相当重要的作用,一般如拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆。

实现拦截器功能主要通过两种途径:
第一种:实现HandlerInterceptor接口
第二种:实现WebRequestInterceptor接口

在实际的应用过程中我们一般还是通过实现 HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类,复写preHandle()、 postHandle()和afterCompletion()这 3 个方法来对用户的请求进行拦截处理的。

在SpringMVC.xml中进行配置:

<!--配置登录拦截器-->
<mvc:interceptors>
	<mvc:interceptor>
		<mvc:mapping path="/**"/><!--拦截所有请求-->
		<mvc:exclude-mapping path="/index.do"/><!--设置允许通过请求-->
		<mvc:exclude-mapping path="/logging.do"/><!--设置允许通过的请求-->
		<bean class="controller.HelloController"/>
	</mvc:interceptor>
</mvc:interceptors>

书写拦截器:

public class CheckLogin implements HandlerInterceptor{
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		HttpSession session = request.getSession();
		// 如果已有登录信息,通过拦截,否则返回false
		if (session.getAttribute("currentUser") != null) {
			return true;
		}else {
			request.setAttribute("message", "请先登录");
			request.getRequestDispatcher("index.do").forward(request, response);
			return false;
		}
	}
	
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
	}
	
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
	}
}

HandlerInterceptor接口是三个方法接收

  1. preHandle:此方法是在前端控制器收到请求以后,配置有拦截器则会先调用拦截器的preHandle()方法,表示可以继续向后调用,如果返回值是false,表示中断请求(不再向后调用),
  2. postHandle:该方法的作用是进行处理器拦截,它执行是处理器处理之后,也就是在controller的方法调用之后执行,但是它会在DispatcherServlet进行视图渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操作。
  3. afterCompletion:整个请求结束之后执行,可以进行一些资源清理工作

拦截器和过滤器的区别

相同:都是AOP(切面编程)思想,都能实现权限检查,日志记录等功能
不同

  1. 使用范围不同:过滤器是Servlet规范中定义的特殊的类,拦截器是Spring框架提供的一种特殊的类,过滤器只能使用在web程序里面,拦截器可以使用在web也可以使用在Application中
  2. 使用资源不同:拦截器是Spring组件,可以使用Sring里面的任何资源,通过IOC注入bean对象,事务管理等,但是过滤器不能。
  3. 拦截深度不同:Filter只能在Servlet中起作用,而拦截器可以深入到方法的前后,异常抛出前后等,拦截器拥有更大的弹性,,故在spring框架里面优先使用拦截器。

八.重定向和请求转发

Spring默认使用转发的方式定位视图,如果需要重定向可以采用一下两种方式:

方式一:使用前缀

@RequestMapping("/forward")
public String login(String userName,String password,Model model) {
	model.addAttribute("userName", userName);
	model.addAttribute("password", password);
	System.out.println(model.toString());
	//return "redirect:show.do"; //重定向
	return "forward:show.do"; //请求转发
}

方式二:如果返回值是一个ModelAndView,使用RedirectView

public ModelAndView checkLogin(String userName ,String  password){
	UserBean user=userService.login(userName ,password );
	RedirectView view=new RedirectView"toIndex.do");
	return  new  ModelAndView(view);
}

九.Spring异常处理

  1. 使用SpringMVC提供的简单异常处理器

通过SimpleMappingExceptionResolver我们可以将不同的异常映射到不同的jsp页面(通过ExceptionMappings属性配置)。同时我们也可以为所有异常指定一个默认的异常提示页面(通过defaultErrorView属性的配置),如果所抛出的异常在exceptionMappings中没有对应的映射,则Spring将用此默认配置显示异常信息。
在SpringMVC配置如下:

<!-- 异常处理一:后端不会报错 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	//发生异常时,默认页面
	<property name="defaultErrorView" value="error"></property>
	<property name="exceptionMappings">
		<props>
			//异常出现时,默认页面
			<prop key="java.lang.Exception">error</prop>
		</props>
	</property>
</bean> -->
  1. 实现HandlerExceptionResolver接口自定义异常处理器
    在SpringMVC.xml中配置如下:
<!-- 异常处理方式二:后端也不会报错 -->
<bean class="cn.goktech.exception.MyExceptionResolver"></bean>

自定义一个异常类:

//自定义异常解析器
public class MyExceptionResolver implements HandlerExceptionResolver{

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object obj,
			Exception ex) {
		System.out.println("进入自定义异常解析器");
		Map<String, Object> map = new HashMap<>();
		map.put("exception", ex);
		//当发生异常时,将异常携带到指定异常处理界面
		return new ModelAndView("error",map);
	}
	
}

3.使用@ExceptionHandler注解实现异常处理,使用@ControllerAdvice实现全局异常处理

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
 * @author 17933
 *定义全局异常处理类
 */
@ControllerAdvice
public class GlobalControllerException {
	
	@ExceptionHandler
	public String testException(Exception e) {
		System.err.println(e.toString());
		System.out.println("这里是全局异常处理类。。。。");
		e.printStackTrace();
		return "error";
	}
}

关于这两个注解的使用,这里有一篇文章写的挺好的:@ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常

十.文件上传

SpringMVC文件上传是通过MultipartResolver(Multipart解析器)处理的,它是一个接口,有以下两个实现类:

1.CommonsMultipartResolver:该方式依赖Apeach下的commons Fileupload项目来处理multipart请求,在使用时必须引入响应的jar包

  • commons-io-2.2.jar和commons-fileupload-1.3.2.jar

2.StandarServletMultipartResolver:他是Spring3.1的产物,不需要引入jar包

CommonsMultipartResolver实现文件上传:

  1. 配置Spring的xml:
<!--CommonsMultipartResolver实现文件上传文件上传:配置id名的时候需要注意,只能是下面的固定名字,否则报错  -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="defaultEncoding" value="utf-8"/>
	<property name="maxUploadSize" value="1048576"/>
</bean>
  1. 使用post提交,并添加enctype属性,设置值为multipart/from-data
<form action="${pageContext.request.contextPath }/upload.do" method="post" enctype="multipart/form-data">
	<div>
		用户名:<input type="text" name="userName">
	</div>
	<div>
		密码:<input type="password" name="password">
	</div>
	<div>
		年龄:<input type="text" name="age">
	</div>
	<div>
		文件一:<input type="file" name="fs">
	</div>
	<div>
		文件二:<input type="file" name="fs">
	</div>
	<div>
		文件三:<input type="file" name="fs">
	</div>
	<div>
		<input type="submit" value="提交">
	</div>
</form>

3.在controller组件上面写文件上传方法:

@RequestMapping("/upload")
public String upLoad(@RequestParam("fs") MultipartFile[]  fs,User user) {
	System.out.println(user.getUserName()+","+user.getPassword()+","+user.getAge());
		
	//文件保存位置
	String uploadPath = "D://SpringUpload";
	File file = new File(uploadPath);
	if (!file.exists()) {
		file.mkdirs();
	}
		
	//源文件--->目标文件
	for (MultipartFile f : fs) {//多文件遍历
		if (f.isEmpty()) {
			continue;
		}
		File filetarget = new File(uploadPath+File.separator+f.getOriginalFilename());
		try {
			f.transferTo(filetarget);
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	return "success";
}

十一.数据验证

  前端页面代码容易被攻击改动,此种验证方式的可靠性并不高,所以当我们对数据的安全性有较高的要求时,会在服务器端也对用户提交的数据进行再次检验,但是如果服务器端通过手写正则表达式来实现数据检验无疑比较繁琐,给我们带来不必要的工作量。
  在Springmvc中我们可以使用其提供的验证器加粗样式Validation,本质就是一个接口)规则进行数据校验。方式是通过JSR-303注解实现对输入内容的验证通过注解@Valid来标明那个Bean需要启用注解式的验证,然后通过该规范提供的一系列注解实现对应规则的数据验证。

  1. 空检查
注解 解释
@Null 被注释的元素必须为null
@NotNull 被注释的元素必须不为null
@NotBlank 验证字符串非null,且长度大于0
@NotEmpty 被注释的字符串必须为非空
  1. boolean验证
注解 解释
@AssertTrue 被注释的元素必须为True
@AssertFalse 被注释的元素必须为false
  1. 数值验证
  • 整数
注解 解释
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
  • 小数
注解 解释
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度
  1. 日期验证
注解 解释
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
  1. 正则验证
注解 解释
@Pattern(regex=) 被注释的元素必须符合指定的正则表达式,只能加在String类型数据上
  1. 长度验证
注解 解释
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
  1. 其他验证
注解 解释
@Email 被注释的元素必须是电子邮箱地址 ,如果为null,不进行验证,算通过验证。
@CreditCardNumber 信用卡验证
@ScriptAssert(lang= ,script=, alias=) 对于复杂业务逻辑可以通过脚本验证
@URL(protocol=,host=, port=,regexp=, flags=) 地址验证

数据验证所需要的jar包;

  • classmate-1.5.0.jar
  • hibernate-validator-6.0.16.Final.jar
  • jboss-logging-3.4.0.Final.jar
  • validation-api-2.0.1.Final.jar
    百度网盘下载:点击下载
    git下载:点击下载
  1. 配置SpringMVC.xml如下:
<!-- 配置数据校验注解 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
	<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
</bean>
<!--自动注册validator-->
<mvc:annotation-driven validator="validator"></mvc:annotation-driven>
  1. 对字段进行注解实现数据校验
ublic class Student {
	@NonNull
	private int id;
	
	@Length(min=2,max=6,message="姓名长度必须为2-6位")
	private String name;
	
	@Pattern(regexp="^[0-9]{6,12}$",message="密码必须为6到12位的数字")
	private String password;
	
	@Pattern(regexp="^1[3-9][0-9]{9}$",message="电话号码格式不正确")
	private String phoneNumber;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}
}
  1. 在控制器里面讲@Valid添加到实体类前面,会对数据进行校验,如果有错误信息会封装到BindingResult实例中getFieldErrors(): 通过该方法返回全部错误信息的集合List, 验证器会将每条错误信息都封装一个FieldError对象中,这里面有包含错误的字段和错提示的message信息。
@RequestMapping("/register")
public String register(@Valid Student student,BindingResult er,Map<String, Object> map) {
	if (er.hasErrors()) {
		List<FieldError> fe = er.getFieldErrors();//将所有错误的校验封装到list里面
		for (FieldError f : fe) {
			//getFiled获取出现错误的字段,getDefaultMessage返回错误提示信息
			System.out.println(f.getField()+"----"+f.getDefaultMessage());
			map.put(f.getField(), f.getDefaultMessage());
		}
	}
	return "register";
}

十二.JSON数据传输

  1. 所需jar包如下:
  • jackson-core-2.5.0.jar 核心jar包
  • jackson-annotations-2.5.0.jar 注解包,提供注解功能
  • jackson-databind-2.5.0.jar 数据绑定包(可选),提供基于“对象绑定”和“树模型”相关API。
  • jackson-core-asl-1.9.7.jar
  • jackson-mapper-asl-1.9.7. jar 这两个包是实现java对象和json数据之间自由转换的。
  1. 后台向页面发送json格式,只需要使用@ResponseBody注解即可。
@RequestMapping("/json")
@ResponseBody   //以json形式返回数据
public User getJson() {
	User  user = new User();
	user.setUserName("Alice");
	user.setAge(18);
	user.setPassword("123456");
	return user;
}
  1. 使用ajax从前端传送数据到后端,单个数据可以使用@RequestParam(“name”)的方式接收,多个数据可以使用@RequestBody 实体类来进行接收,或则使用Map接收。
@RequestMapping("/login")
@ResponseBody
public String ajax(@RequestBody User user,Model model) {
	System.out.println("username="+user.getUserName());
	if (user.getUserName().equals("这是一只萌猫")) {
		return "true";
	}
	return "false";
}
发布了26 篇原创文章 · 获赞 27 · 访问量 6870

猜你喜欢

转载自blog.csdn.net/qq_40705355/article/details/98472723