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

posted @ 2020-01-01 21:05  JAHC  阅读(158)  评论(0)    收藏  举报