该标签用来指定对应的控制器的请求路径
package com.zl.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
//父路径
@RequestMapping("helloSpringMVC")
public class HelloSpringMVC {
//请求路径
@RequestMapping("hello.do")
public ModelAndView hello() {
ModelAndView mv=new ModelAndView();
System.out.println(".....................");
mv.setViewName("main");
return mv;
}
}
在控制器类中,处理客户端请求后,我们也可以把需要响应到页面的数据和视图名字都封装到一个ModelAndView对象中,然后直接返回这个ModelAndView对象,代码如下:
@RequestMapping(value="sr") public ModelAndView secondRequest(Model model,HttpServletRequest request){ String msg = request.getParameter("msg"); System.out.println("接收到页面传递的参数,msg:"+msg); String key = "hello world,"+msg; ModelAndView mav = new ModelAndView(); mav.addObject("key", key); mav.addObject("yyyyy"); mav.setViewName("show"); return mav; }
这里,需要注意ModelAndView的包,要导入如下的包:
import org.springframework.web.servlet.ModelAndView;
通过servlet原生的API:
通过和表单name属性值一致的参数接收
① @RequestParam:用来绑定需要把那个表单数据设置给该属性
通过实体类来接收表单数据
接收多选框的值
① 如果在形参中单独接收需要使用数组类型
② 如果封装到对象里面那么使用集合类型(List)
接收时间
通过形参注入的request设置值
方法的对象类型形参默认会放置在request作用域中,使用参数类名首字母小写作为key
放在ModelAndView里面的数据默认也会放置在request作用域中
如果形参为Map,Model,ModelMap…集合里面的数据也会自动放到request中
通过HttpSession设置数据
@SessionAttributes可以把request作用域中的数据同步到session中
在项目中,有时候我们需要从控制器的一个方法中跳转到另一个方法中,此时我们的处理方式,可以通过转发或者重定向来完成。
springMVC中主要提供了两种跳转方式:客户端跳转(redirect)和服务器端跳转(forward)。两种跳转方式的实现代码如下:
@RequestMapping(value="islogin") public String islogin(Emp emp){ System.out.println("执行islogin,完成登录判断.."); System.out.println("接收到页面传递的参数:"+emp.getLoginname()+","+emp.getLoginpwd()); //return "suc"; //redirect : 重定向 //forward : 转发 //两个都能完成方法跳方法的功能 //区别:1.redirect不能传递参数,forward在跳转时能够传递参数 //2.redirect跳转时,地址栏的地址会发生变化;forward在跳转时,地址栏的地址没有发生变化 //3.redirect属于客户端跳转;forward属于服务器端跳转 //4.redirect至少发送了2次以上的请求;forward只发了一次请求 //5.a如果是处理的Post请求,那么:转发时,只能转发到post方法里;但是可以重定向到Get方法里 //a如果是处理的get请求,那么:转发时,只能转发到GET方法里;重定向也只能到达GET方法里 return "redirect:/sc/findall"; //return "forward:/sc/findall"; } @RequestMapping(value="findall") public String findallemp(Emp emp){ System.out.println("findallemp..."); System.out.println("接收emp参数:"+emp.getLoginname()+","+emp.getLoginpwd()); return "suc"; }
/*
* ajax登录
*
*/
@RequestMapping("ajaxLogin.do")
@ResponseBody
public Map ajaxLogin(User user){
Map json=new HashMap();
if("张三".equals(user.getName())&&"123456".equals(user.getPad())) {
json.put("mess", true);
}else {
json.put("mess", false);
}
return json;
}
/*
* 图片上传
*/
@RequestMapping("fileUpload.do")
//这里必须用@RequestParam绑定参数
public ModelAndView fileUpload(@RequestParam("img") CommonsMultipartFile img) {
ModelAndView mv=new ModelAndView();
//判断用户有没上传图片
if(img.getSize()>0) {
//获取原始文件名称
String oldFileName=img.getOriginalFilename();//aaa.jpg
//创建新文件名称
String newFileName=UUID.randomUUID().toString()+oldFileName.substring(oldFileName.lastIndexOf("."));
//创建新文件
File newFile=new File("D:/apache-tomcat-8.0.50/webapps/img/"+newFileName);
//如果文件不存在我们手动创建出来
if(!newFile.exists()) {
newFile.mkdir();
}
//把旧文件中的数据写新文件中
try {
img.transferTo(newFile);
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
mv.setViewName("redirect:/admin/mian.jsp");
}
return mv;
}
spring整合第三方的验证框架对表单进行验证,需要导入表单验证框架的jar包
常用的表单验证注解
空检查
@Null:验证对象是否为null
@NotNull:验证对象是否不为null,无法查检长度为0的字符串
@NotBlank:检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格
@NotEmpty:检查约束元素是否为NULL或者是EMPTY,size>0 Booelan检查
@AssertTrue:验证Boolean对象是否为true
@AssertFalse:验证Boolean对象是否为false
长度检查
@Size(min=,max=)验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=,max=)验证对象(CharSequence子类型)长度是否在给定的范围之内
日期检查
@Past:验证Date和Calendar对象是否在当前时间之前
@Future:验证Date和Calendar对象是否在当前时间之后
@Pattern:验证String对象是否符合正则表达式的规则
数值检查
@Min:验证Number和String对象是否大等于指定的值
@Max:验证Number和String对象是否小等于指定的值
@DecimalMax被标注的值必须不大于约束中指定的最大值.这个约束的参数
是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin:被标注的值必须不小于约束中指定的最小值.这个约束的参数
是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits:验证Number和String的构成是否合法
@Digits(integer=,fraction=):验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度
@Range(min=,max=):检查数字是否介于min和max之间
@CreditCardNumber:信用卡验证
@Email:验证是否是邮件地址,如果为null,不进行验证,算通过验证
@ScriptAssert(lang=,script=,alias=):通过脚本验证
在需要进行验证的实体类对象对应的属性上用注解声明验证内容
package com.zl.pojo;
import java.util.Date;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
public class User {
@NotEmpty(message="用户名不能为空")
private String name;
@Size(min=6,max=10,message="密码长度在6-10位之间")
private String pad;
private List aihao;
private Role r;
@DateTimeFormat(pattern="yyyy-MM-dd")
@Past(message="生日必须在当前日期之前")
@NotNull(message="日期不能为空")
private Date bir;
//getset省略
}
在指定的controlle方法中对该对象进行验证
/*
* 表单验证:
* BindingResult:错误的信息都会包含在该对象中,注意的是该对象必须紧挨验证对象
*/
@RequestMapping("formVaild.do")
public ModelAndView formVaild(@Valid User user,BindingResult br) {
ModelAndView mv=new ModelAndView();
//说明验证没有通过
if(br.hasErrors()) {
for(ObjectError e:br.getAllErrors()) {
System.out.println(e.getObjectName()+":"+e.getDefaultMessage());
}
mv.setViewName("/login");
}else {
mv.setViewName("/admin/main");
}
return mv;
}
在页面可以通过特定标签取出错误消息,注意使用form标签的页面必须经过spring
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
通过@ExceptionHandler注解标识的方法可以捕获该handler执行过程中所有controller出现的异常,方便进行异 常的统一处理
/*
* 统一异常处理方法:
* 当该handler里面的方法执行过程中出现异常都会进入到该方法
*/
@ExceptionHandler(Exception.class)
public ModelAndView error(Exception ex) {
ModelAndView mv=new ModelAndView();
if(ex instanceof ArithmeticException) {
System.out.println("这是算数异常....");
}else if(ex instanceof MaxUploadSizeExceededException) {
System.out.println("异常捕获到.....");
mv.addObject("err", "图片过大....");
mv.setViewName("redirect:/login.jsp");
}
return mv;
}
## 乱码的处理##
在编码过程中,因为参数的传递过程,编码环境的不一致,经常会导致乱码的出现,springMVC提供了一个过滤器,可以用来处理乱码问题,只需要我们在web.xml中直接配置即可:
java
characterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
characterEncodingFilter
/*
encoding:字符集,即将过滤到的request的字符集设置为encoding指定的值,如UTF-8等;
forceEncoding:字面意思是强制字符集,但你大可不必按字面意思理解,因为这个参数的值只不过是指定response的字符集是否也设置成encoding所指定的字符集,所以你可以选择设置为true或false。默认为false。
SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那样子判断当前时间是否是购票时间。
HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
(1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解释我们知道这个方法包括后面要说到的afterCompletion 方法都只能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用。postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行,这和Struts2 里面的Interceptor 的执行过程有点类型。Struts2 里面的Interceptor 的执行过程也是链式的,只是在Struts2 里面需要手动调用ActionInvocation 的invoke 方法来触发对下一个Interceptor 或者是Action 的调用,然后每一个Interceptor 中在invoke 方法调用之前的内容都是按照声明顺序执行的,而invoke 方法之后的内容就是反向的。
(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
package com.zl.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.zl.pojo.User;
public class MyInterceptor1 implements HandlerInterceptor{
/*请求(方法)执行完成以后执行
* 做一些清理的工作,以及记录日志的操作
* 该方法执行的前提是preHandle方法返回true
* 逆向执行
*/
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("请求完成之前:拦截器1");
}
/*
* 方法执行完成但是在视图解析(渲染)之前执行
* 该方法执行的前提是preHandle方法返回true
* 逆向执行
*/
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
//在这里可以对ModelAndView对象进行操作
System.out.println("视图渲染之前:拦截器1");
}
/*
* 请求到达方法之前执行
* 返回值:当我们想让请求通过拦截器返回true,否则返回false
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("方法之前:拦截器1");
User u=(User) request.getSession().getAttribute("loginUser");
if(u==null) {
arg1.sendRedirect(request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/"+"login.jsp");
return false;
}else {
return true;
}
}
}