springMVC
目录
1.概念
2.注解开发
2.1controller中方法的返回值
2.2 controller中方法参数的绑定
3.服务端校验
3.1普通校验
3.2 分组校验
3.3 @ModelAttribute()做数据回显
4. 全局异常处理
5.与Json的数据交互
6.springmvc的图片上传
一、概念
springmvc是spring框架的一个模块,spring和springmvc之间无需通过中间整合层的整合。
springmvc是一个基于mvc的web框架。mvc是一种设计模式。
模式流程图:

上面的逻辑步骤:我们只需要去开发 "Handler处理器" 和 "视图view"
并且需要配置一下 "前端控制器DispatcherServlet"
springmvc的配置开发。可以在下面的笔记中找到。
二、注解开发
使用到@RequestMapping( value = "url" ) 的窄化思想。
(1) 进行url请求的一个分类请求。
(2) 还可以使用@RequestMapping( value = "url" , method={RequestMethod.POST} ) 限制HTTP请求方式
controller中方法的返回值
1、返回model and view :返回时,需要定义ModelAndView,并分开进行设置
public ModelAndView text1(){ ModelAndView modelAndView = new ModelAndView("success");
Student student = new Student(); student.setId(1); student.setName("zs"); modelAndView.addObject("student",student); return modelAndView; }
2、返回字符串:
(1)返回逻辑视图名
@RequestMapping(value = "text2") public String text2() { return "success.jsp"; }
(2)重定向 (redirect)
使用重定向浏览器的地址栏会变化,并且request中的数据无法共享。
@RequestMapping(value = "text3") public String text3() {
//重定向到text2的连接中 return "redirect:text2.action"; }
(3) forward页面转发
使用页面转发,浏览器地址栏不会改变,并且request中的数据可以共享。
@RequestMapping(value = "text3") public String text3() { //重定向到text2的连接中 return "forward:text2.action"; }
3、没有返回值 void
不设置返回值时,可以使用request、response参数进行响应结果
(1) request的请求转发
request.getRequestDispatcher("页面路径").forward(request,response);
(2) response的重定向
reponse.sendRedirect("URL");
(3) reponse指定响应结果 (如响应Jsion)
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
方法参数的绑定
(1) 简单类型
如果直接接受,则需要方法中的形参和提交的name的名称一致。
如果使用@RequestParam绑定。则不要钱名称要一致。
@RequestParam的三个参数:
value:指定值、
required:是否一定要传参
dafaultValue:默认值。如果设置了。required就会失效。自动使用默认值。
@RequestMapping(value = "text4") public String text4(@RquestParam(value="name",required="true") String name) { System.out.println(name+"使用了注解"); return "success.jsp"; }
(2)自定义对象类型
只需要input中传入的name的名称和自定义类中的属性一致。
@RequestMapping(value = "text5") public String text5(User user) String name) { System.out.println(user.id + ""+ user.name); return "success.jsp"; }
//页面
<input type="text" name="id">
<input type="text" name="name">
(3) 如果是复合类型
就是一个类中。又应用了另外一个类来作为当前类的属性。
public class User{
String name;
//补全get、set方法
}
public class Person{
User user;
int num;
//补全get、set方法
}
@RequestMapping(value = "text6")
public String text6(Person person) String name) {
System.out.println(person.getNum());
System.out.println(person.getUser().getName());
return "success.jsp";
}
//页面
<input type="text" name="num">
<input type="text" name="user.name">
(4) 数组类型
一般用于批量操作,页面传过来的是一个数组类型的信息。
@RequestMapping(value = "text7") public String text7(Integer[] id) String name) { //处理 return "success.jsp"; } //页面 <input type="text" name="id"> //多条name为id的text
(5) List集合类型
List不同于数组。不可以直接在controller中接收。需要使用包装类。
其他集合也是一样。使用包装类进行多个信息的绑定。
public class User{
String name;
//补全get、set方法
}
public class UserListForm{ //定义包装类
List<User> users;
//补全get、set方法
}
@RequestMapping(value = "text8")
public String text8(UserListForm userlist) String name) {
//遍历处理
return "success.jsp";
}
//页面 下标由0开始。通过点获取User中的属性
<input type="text" name="users[0].name">
三、服务端校验
(1)导入对应的jar包。

一些校验注解:
@Null 被注解的元素必须为空
@NotNull 被注解的元素必须不为空
@AssertTrue 被注解的元素必须为true
@AssertFlase 被注解的元素必须为false
@Min(value) 被注解的元素必须是数字,且必须大于指定的最小值
@Max(value) 被注解的元素必须是数字,且必须小于指定的最大值
@DecimalMin(value) 被注解的元素必须是数字,且必须大于指定的最小值
@DecaimalMax(value) 被注解的元素必须是数字,且必须小于指定的最大值
@Size(max=,min=) 被注解元素的大小必须在指定的范围内
@Digit(integer,fraction) 被注解元素必须是数字,且其值必须在可接受的范围内
@Past 被注解元素必须是一个过去的日期
@Futrue 被注解元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注解元素必须符合指定的正则表达式
@NotBlank 验证非空,且长度必须大于0
@Email 被注解的元素必须是电子邮件地址
@Length(max=,min=) 被注解的字符串大小必须在指定的范围内
@NotEmpty 被注解的字符串必须非空
@Range(max=,min=) 被注解的元素必须在指定范围内
普通校验
(2) 编写错误提示文件 ValidationMessages.properties
注意:一定要配置为src根目录下。并且不要改名
user.name.emptry=不能为空
user.password.size=密码长度为3-6位
(3) 配置springmvc文件
<!-- 开启扫描 扫描包路径-->
<context:component-scan base-package="com.springmvc.controller"></context:component-scan>
<!-- 开启SpringMVC注解 -->
<mvc:annotation-driven validator="validator"></mvc:annotation-driven>
<!--添加对JSR-303验证框架的支持 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
<property name="validationMessageSource" ref="validatemessageSource"/>
</bean>
<bean id="validatemessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:ValidationMessages"/> //配置错误文件
<property name="defaultEncoding" value="utf-8"/>
<property name="cacheSeconds" value="120"/>
</bean>
(4) 在bean中配置校验规则
public class User{ //配置校验规则
@Null(message="{user.name.emptry}") String name;
@Size(max=6,min=3,message="{user.password.size}")
String password; }
(5)controller中使用
@Validated和BindingResult的顺序不能捣乱
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/add") public String text(@Validated User user,BindingResult br,Model model) {
//获取提示错误信息 List<ObjectError> allErrors = br.getAllErrors(); for (ObjectError objectError : allErrors) { System.out.println(objectError.getDefaultMessage()); } model.addAttribute("errors", allErrors); //在页面中显示错误 ${}获取 return "success.jsp"; } }
(6) 页面中显示错误
<c:if test="${ errors != null}"> <c:forEach items="${errors}" var="e"> ${e.defaultMessage} </c:forEach> </c:if>
分组校验
因为不用的controller的校验是不同的,定义了分组,就可以在不同的controller中调用不同的分组进行校验
(1) 在javabean中设置分组
public class User{ //配置校验规则
@Size(message="{user.name.emptry}",groups=(ValidGroups1.class))
@Size(max=6,min=3,message="{user.password.size}",groups=(ValidGroups2.class)) int password; }
(2) 创建分组接口类
不需要定义任何的方法。仅仅是为了对不用的校验进行分组
public interface ValidGroups1{ } public interface ValidGroups2{ }
(3) controller中调用
@RequestMapping("/add") public String text(@Validated(value = ValidGroups1.class) User user,BindingResult br,Model model) { //这样。在本方法中就可以使用分组中的ValidGroups1进行校验了 return "success.jsp"; }
@ModelAttribute()做数据的回显
因为@ModelAttribute()会在controller中的方法执行前被执行。所以。如果controller中有多个URL映射的,要小心使用
(1) 注解无返回值方法void
在页面请求/helloWorld?name = huang,controller会先执行createModel方法。把传来的参数加入到名为attributeName的model属性中,helloWorld方法被调用后。会返回视图名和封装好的ModelAttribute (注意:一定要传入@ModelAttribute 方法中对应的形参)
@Controller public class textcontroller{
@ModelAttribute //页面访问的时候,需要有一个参数String传过来。 public void createModel(@RequestParam String name, Model model) { model.addAttribute("attributeName", name); }
@RequestMapping(value = "/helloWorld") public String helloWorld() { return "helloWorld"; } }
//页面调用 ${attributeName}
(2) 注解返回具体类
返回具体的类的类型。如果不用value来指定@ModelAttribute的属性名。则返回类型,就是属性名。
@Controller public class textcontroller2{ @ModelAttribute //如果指定属性名 @ModelAttribute(value="model1") public User populateModel() { User user=new User(); user.setName("huang"); return user; } @RequestMapping(value = "/helloWorld2") public String helloWorld() { return "helloWorld.jsp"; } }
//页面调用
//不设置属性名 ${User.name}
//设置属性名 ${model1.name}
(3)@ModelAttribute和@RequestMapping注解同一个方法
这时候的方法返回值不是代表视图名。而是model的属性值。视图名称由RequestToViewNameTranslator根据请求"/helloWorld3.do"转换为逻辑视图helloWorld3。Model属性名称有@ModelAttribute(value=””)指定,相当于在request中封装了key=name,value=huang。
@Controller public class textcontroller3{ @RequestMapping(value = "/helloWorld3.do") @ModelAttribute("name") public String helloWorld() { return "huang"; } }
(4)注解一个方法的参数
方法helloWorld的参数user的值来源于addName()方法中的model属性。此时如果方法体没有标注@SessionAttributes("user"),那么scope为request,如果标注了,那么scope为session
也可以从form表单、URL中获取(其实不注解指定也可以获取到)
@Controller public class textcontroller4{ @ModelAttribute("user") public User addName() { return new User("huang","123"); } @RequestMapping(value = "/helloWorld4") public String helloWorld(@ModelAttribute("user") User user) { user.setUserName("can"); return "helloWorld"; } }
//从form、URL获取
@RequestMapping(value = "/helloWorld5")
public String helloWorld(@ModelAttribute User user) {
return "helloWorld";
}
(5) 可以做特定的控制权限管理
需要在基类方法中控制写此注解,需要控制权限的控制器,继承控制器就可以了。
public class BaseController { @ModelAttribute public void populateModel() throws Exception { SysUser user = ContextUtil.getCurrentUser(); if(user.getAccount().equals("admin")){ throw new Exception("没有权限"); } } } @Controller //继承基类 public class Hello2ModelController extends BaseController { @RequestMapping(value = "/helloWorld7") public String helloWorld(@ModelAttribute("myUser") User user) { user.setName("huang"); return "helloWorld.jsp"; } }
四、全局异常处理器
在系统遇到异常的时候。全局处理器会解析异常类型。
如果是系统的异常,直接取出异常信息在页面上展示。
如果不是系统的异常,需要程序员构造一个异常类型。并返回错误提示信息。
//定义异常处理器。 //只要实现了 HandlerExceptionResolver 接口。就是全局异常处理器 public class exceptioneds implements HandlerExceptionResolver { @Override public ModelAndView resolveException( HttpServletRequest request,
HttpServletResponse response , Object handler, Exception ex ){
CustomException cunstomexception = null; if( ex instanceof CustomException){ //判断异常类型 cunstomexception = (CustomException)ex; //系统异常 }else{ cunstomexception = new CustomException("未知错误"); } //错误信息 String message = cunstomexception.getMessage();
ModelAndView modelandview = new ModelAndView(); //把错误信息传给页面展示 modelandview.addObject( "message ", message ); //返回页面 modelandview.setViewName("error");return modelandview; } }
//在springmvc配置文件上配置全局处理器的bean
<bean class="exceptioneds"></bean> //配置上面类的包路径
五、拦截器
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。使用拦截器需要几个步骤:
(1) 定义拦截器 (就是需要HandlerInterceptor接口)
实现HandlerInterceptor接口,需要进行三个方法的重写。各自代表不同的含义
public class handlerinterceptor implements HandlerInterceptor{//实现接口
//(1) 这个方法有 (请求、相应、对象) 进入Handler方法之前执行(用于身份验证、身份授权、) @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { // TODO Auto-generated method stub //false:表示拦截,不向下执行 //true:表示放行。 return false; }
//(2) 这个方法有 ModelAndView : 进入Handler之后,返回ModelAndView之前执行:
//应用场景从ModelAndView出发: 将公用的模型数据(比如菜单导航,)在这里传到视图,也可以在这里统一指定视图。 @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception { // TODO Auto-generated method stub }
//(3) 这个方法有异常: 执行Handler之后执行: 应用场景:统一异常处理、统一日志处理。 @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { // TODO Auto-generated method stub } }
(2) 配置拦截器
配置有两种方法,一是基于HanlerMapping的拦截。二是基于全局的拦截。
//(1)首先需要补全schema约束。(这里可能不全,配置适合自己的jar包的约束) xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" //(2) 配置HandlerMapping的拦截器 <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/Login.action"> //配置请求路径 <bean class="com.handlerinterceptor"></bean> //定义的拦截器的路径 </mvc:mapping> </mvc:interceptor> </mvc:interceptors> //(2)配置全局拦截器。在<mvc:interceptors>根下配置拦截器。 <mvc:interceptors> <bean class="com.handlerinterceptor"></bean> //全局都会使用这个拦截器 </mvc:interceptors>
六、Json的数据交互
有两种方式:

(1) 在开发前需要配置环境。导入对应的jar包
jackson-core、jackson-mapper的jar包
(2) 在配置文件中配置转换器
<mvc:annotation-driven />
(3) 交互转换设置 (两种请求情况)
1、请求是Json,返回Json
//(1) 请求的是Json串,返回Json串 $.ajax({ type = 'post', url = '/login.action', contentType : 'application/json;charset=utf-8', //数据提交的是json串 data : '{"name":"huang","password":123}', success : function(data){ alert(data); } }) //controller方法设置 @RequestMapping(value="login") public @ResponseBody User getUserJson( @RequestBody User user ){ //@RequestBody 将Json --》 java对象 //@ResponseBody 将java对象 ---》 Json串 return user; }
2、请求时key/value,返回时Json (默认是key/value)
$.ajax({ type = 'post', url = '/login.action', //数据提交的是key/value串 data : 'name=huang & password=123', success : function(data){ alert(data); } }) //controller方法设置 @RequestMapping(value="login") public @ResponseBody User getUserJson(User user ){ //@ResponseBody 将java对象 ---》 Json串 return user; }
六、扩展springmvc的图片上传
这里介绍一种方法,也是我自己用的比较多的方法。就是从页面上传图片到server,然后定义图片封装设置类,将图片保存在自己项目中的指定文件夹里。(应该是放到服务器比较好些的。后续改进)
(1) 定义图片封装设置类
public class tools { public void FileUpload(HttpServletRequest request, MultipartFile file) throws IllegalStateException, IOException { // 创建保存的路径 项目中有指定的文件夹 String url = "/image"; // 保存真实路径 String realUrl = request.getSession().getServletContext().getRealPath(url); // 创建真实路径的文件 File newfile = new File(realUrl); if (!newfile.exists()) newfile.mkdirs(); if (!file.isEmpty()) { // 直接获取上传图片的名称 String photoname = file.getOriginalFilename(); // 拼接完整路径 String photoFilePath = newfile + File.separator + photoname; File photoBookFile = new File(photoFilePath); file.transferTo(photoBookFile); // 转传 } } }
(2) 页面上传form
//一定要指定enctype="multipart/form-data" <form action="/text.action" method="post" enctype="multipart/form-data"> <input type="file" class="custom-file-input" name="picture">
(3) controller方法接收并处理
@RequestMapping(value = { "/text" }, method = { RequestMethod.POST })
public String text(@RequestParam(value = "picture", required = false) MultipartFile picture){
//在本类中继承图片封装设置类
this.FileUpload(request, picture);// 图片传入项目文件夹中
return "success.jsp";
}
上面是基本的springmvc。
详细的讲解可以到官网学习:https://docs.spring.io/spring/docs/5.2.2.RELEASE/spring-framework-reference/web.html#spring-web

浙公网安备 33010602011771号