Spring Mvc (三)


Spring mvc 的RESTful集成

RESTful是当前比较流行的互联网架构模型,通过统一的规范来完成不同端的数据访问和交互,RESTful(资源表现层状态转化)

优点:结构清晰,有统一的标准,扩展性好

  • Resources
    资源是指网路中的某个具体文件,可以是文件、图片、视频、音频等,是网路中真实存在的一个实体。
    获取它:可以通过统一资源定位负找到这个实体,URL,每个资源都有一个特定的URL,通过URL就可以找到一个具体的资源
  • Pepersentation
    资源表现层,资源的具体表现层次,例如一段文字、可以用TXT、HTML、XML、JSON、等不同的形式来描述它。
  • State Transfer
    状态转化是指客户端和服务器之间的数据交互,因为HTTP请求不能传输数据的状态,所有的状态都保存在服务器端,如果客户端希望访问到服务器的数据,就需要使其发生状态改变,同时这种状态的改变是建立在表现层上的。
    RESTful的特点:
    1.URL传递参数更加简洁
    2.完成不同总端之间的资源共享,RESTful提供了一套规范,不同的终端之间只需要遵守规范,就可以实现数据的交互
    RESTful四中表现类型,
    HTTP中的:
  • GET 获取资源
  • POST创建资源
  • PUT修改资源
  • DELETE删除资源

基于RESTful的方式,增删改查分别操作使用不同的HTTP请求来访问。

传统的from表单只支持GET和POST

解决方法:

添加HiddenHttpMeethodFilter过滤器将POST转化为PUT或DELETE

HiddenHttpMeethodFilter实现原理:

HiddenHttpMeethodFilter检测请求的参数是否包含_method参数,如果包含则取出它的值,并且判断它的请求类型之后完成请求的类型的转换,然后继续传递。

实现步骤

1.在from表单中加入隐藏域的标签,name为_method,value为DELETE/PUT

<%--
  Created by IntelliJ IDEA.
  User: 郝泾钊
  Date2022-04-07
  Time14:10
  To change this template use File | Settings | File Templates.
--%>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Titletitle>

head>
<body>
    <form action="/update" method="post">
        <input type="hidden" name="_method" value="PUT">
        <input type="submit" value="提交">
    form>
        <form action="/delete" method="post">
        <input type="hidden" name="_method" value="DELETE">
        <input type="submit" value="DELETE提交">
    form>
body>
html>
  1. web.xml配置
    HiddenHttpMthodFilter org.springframework.web.filter.HiddenHttpMethodFilter
    HiddenHttpMthodFilter /*

3.控制器

@PutMapping("/update")
@ResponseBody
public  String update(){
    return "PUT已接受到请求";
}

@DeleteMapping("/delete")
public  String delete(){
return "DELETE已接受请求";
}

需求分析

  • 添加课程,成功返回全部课程信息
  • 查询课程,通过id查找课程
  • 修改课程,成功返回全部的课程信息
  • 删除课程,成功返回删除之后的全部课程信息

代码实现

  1. JSP
  • 添加课程
  • 修改课程
  • 课程展示

2.Course实体类

package com.southwind.entity;

import lombok.Data;

@Data
public class Course {
    private Integer id;
    private String name;
    private  Double prive;
}

3.CourseRepository

package com.southwind.respository;

import com.southwind.entity.Course;
import org.springframework.stereotype.Repository;

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


@Repository
public class CourseRepository {
    private Map courseMap;
    public CourseRepository(){
        courseMap=new HashMap<>();
        courseMap.put(1,new Course(1,"java基础",Double.parseDouble("500")));
        courseMap.put(2new Course(2"java高级", Double.parseDouble("500")));
        courseMap.put(3new Course(3"企业级框架", Double.parseDouble("500")));
    }
    public Collection findAll(){
        return courseMap.values();
    }
    public Course findById(Integer id){
        return  courseMap.get(id);
    }
    public  void saveOrupdate(Course course){
        courseMap.put(course.getId(),course);
    }
    public void  delete (Integer id){
        courseMap.remove(id);
    }
}

4.CourseController:

package com.southwind.controller;

import com.southwind.entity.Course;
import com.southwind.respository.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/course")
public class CourseController {
    @Autowired
    private CourseRepository courseRepository;
    @PostMapping("/save")
    public  String save(Course course){
        courseRepository.saveOrupdate(course);
       return "redirect:/course/findAll";
    }
    @GetMapping("/findAll")
    public ModelAndView findAll(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("index");
        modelAndView.addObject("list",courseRepository.findAll());
        return modelAndView;
    }
    @DeleteMapping("/delete/{id}")
    public String deleteById(@PathVariable("id")Integer id){
        courseRepository.delete(id);
        return  "redirect:/course/findAll";
    }
    @GetMapping("/findById/{id}")
    public ModelAndView findById(@PathVariable("id") Integer id){
        ModelAndView modelAndView =new ModelAndView();
        modelAndView.setViewName("edit");
        modelAndView.addObject("course",courseRepository.findById(id));
        return modelAndView;
    }
    @PutMapping("/update")
    public  String update(Course course){
        courseRepository.saveOrupdate(course);
        return "redirect:/course/findAll";
    }
}

4.jsp

  • 首页(查询和删除修改)
    <%-- Created by IntelliJ IDEA. User: 郝泾钊 Date: 2022-04-07 Time: 10:50 To change this template use File | Settings | File Templates. --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@page isELIgnored="false"%>

    Title



    {course.id}

              
          
      


  • <%-- Created by IntelliJ IDEA. User: 郝泾钊 Date: 2022-04-07 Time: 15:38 To change this template use File | Settings | File Templates. --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@page isELIgnored="false"%>

      Title
    
    
      
          
          

  • 编号 名称 价格 删除
    {course.price}
    {course.id}">修改
    编号:
    名称:
    价格:

  • <%-- Created by IntelliJ IDEA. User: 郝泾钊 Date: 2022-04-07 Time: 15:10 To change this template use File | Settings | File Templates. --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>

      Title
    
    
      

    课程编号
    课程名称
    课程价格

SpringMvc的文件上传下载:

文件上传

单文件上传

1.底层使用的是Apache fileupload组件进行上传的功能,Springmvc 只是对其进行了封装,简化开发,

pom.xml


    <dependency>
      <groupId>commons-fileuploadgroupId>
      <artifactId>commons-fileuploadartifactId>
      <version>1.3.3version>
    dependency>
    <dependency>
      <groupId>commons-iogroupId>
      <artifactId>commons-ioartifactId>
      <version>2.6version>
    dependency>

2.JSP页面处理

  • inpu的type设置为file
  • form表单的method设置为post
  • form表单的enctype设置为multipar/form-data
    一:单文件:

JSP

<%--
  Created by IntelliJ IDEA.
  User: 郝泾钊
  Date: 2022-04-07
  Time: 16:06
  To change this template use File | Settings | File Templates.
--%>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false"%>
<html>
<head>
    <title>Titletitle>
head>
<body>
    <form action="/file/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="img"/>
        <input type="submit" value="提交"/>
    form>
<img src="${src}">
body>
html>

Handler

package com.southwind.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

@Controller
@RequestMapping("/file")
public class fileHandler {
    @PostMapping("/upload")
    public String upload(@RequestParam("img")MultipartFile img, HttpServletRequest request) {
        if(img.getSize()>0){
            String path =request.getSession().getServletContext().getRealPath("file");
            String fileName =img.getOriginalFilename();
            File file =new File(path,fileName);
            try {
                img.transferTo(file);
                request.setAttribute("src","/file/"+fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return "upload";
    }
}

配置解析器:


<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">bean>

二:多文件:

@PostMapping("/uploads")
public String uploads(@RequestParam("imgs")MultipartFile[] imgs, HttpServletRequest request) {
    List<String> pathlist = new ArrayList<>();
    for (MultipartFile img : imgs) {
        if (img.getSize() > 0) {
            String path = request.getSession().getServletContext().getRealPath("file");
            String fileName = img.getOriginalFilename();
            File file = new File(path, fileName);
            try {
                img.transferTo(file);
                pathlist.add("/file/" + fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
    request.setAttribute("list",pathlist);
    return "upload";
}

"/file/uploads" method="post" enctype="multipart/form-data">
        file1:"file" name="imgs">

        file1:"file" name="imgs">

        "submit" value="提交">

"${list}var="path">
    "${path}" width="300px">

文件下载

@GetMapping("/downLoad")
public void downLoad(String fileName, HttpServletRequest request, HttpServletResponse response){
    if(fileName!=null){
        String path = request.getSession().getServletContext().getRealPath("file");
        File file =new File(path,fileName);
        OutputStream outputStream=null;
        if(file.exists()){
            //设置下载文件
            response.setContentType("application/force-downlocad");
            //设置文件名
            response.setHeader("Content-Dispoition","attachment;filename"+fileName);
            try {
                outputStream=response.getOutputStream();
                outputStream.write(FileUtils.readFileToByteArray(file));
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(outputStream!=null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

Spring Mvc 数据校验的组件

有两种:

  • 基于Vaildator接口进行校验

  • 使用Annotation JSR-303标准校验
    使用Vaildator接口会复杂点,开发者要自己定义规则,而Annotation JSR-303则是要开发者添加对应的校验注解即可。
    基于Validator的接口*
    1.创建实体类:
    package com.southwind.entity;

    import lombok.Data;

    @Data
    public class Student {
    // private Integer id;
    // private String name;
    // private Integer age;
    private String name;
    private String password;
    }
    2.自定义数据校验器StudentValidator实现Validator接口,重写接口的抽象方法,加入校验规则。
    package com.southwind.validation;

    import com.southwind.entity.Student;
    import org.springframework.validation.Errors;
    import org.springframework.validation.ValidationUtils;
    import org.springframework.validation.Validator;

    public class StudentValidator implements Validator {

      @Override
      public boolean supports(Class<?> aClass) {
          return Student.class.equals(aClass);
      }

      @Override
      public void validate(Object o, Errors errors) {
          ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
          ValidationUtils.rejectIfEmpty(errors,"password",null,"密码不能为空");
      }

    }

3.业务方法:

package com.southwind.controller;

import com.southwind.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/validatior")

public class ValidatiorHandler {
    //先数据绑定
    @GetMapping("/login")
    public String  login(Model model){
        model.addAttribute(new Student());
        return  "login";
    }
    @RequestMapping("/login")
    public String login(@Validated Student student, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return "login";
        }else {
            return "login";
        }
    }
}

package com.southwind.validation;

import com.southwind.entity.Student;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class StudentValidator implements Validator {

    @Override
    public boolean supports(Class<?> aClass) {
        return Student.class.equals(aClass);
    }

    @Override
    public void validate(Object o, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
        ValidationUtils.rejectIfEmpty(errors,"password",null,"密码不能为空");
    }
}

Annotation JSR-303

Hibernater Validator,通过注解完成校验

名称 说明
@Null 被标注的元素必须为 null
@NotNull 被标注的元素必须不为 null
@AssertTrue 被标注的元素必须为 true
@AssertFalse 被标注的元素必须为 false
@Min(value) 被标注的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被标注的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMax(value) 被标注的元素必须是一个数字,其值必须大于等于指定的最大值
@DecimalMin(value) 被标注的元素必须是一个数字,其值必须小于等于指定的最小值
@size 被标注的元素的大小必须在指定的范围内
@Digits(integer,fraction) 被标注的元素必须是一个数字,其值必须在可接受的范围内;integer 指定整数精度,fraction 指定小数精度
@Past 被标注的元素必须是一个过去的日期
@Future 被标注的元素必须是一个将来的日期
@Pattern(value) 被标注的元素必须符合指定的正则表达式

配置:

pom.xml


    <dependency>
      <groupId>org.hibernategroupId>
      <artifactId>hibernate-validatorartifactId>
      <version>5.3.6.Finalversion>
    dependency>
    <dependency>
      <groupId>javax.validationgroupId>
      <artifactId>validation-apiartifactId>
      <version>2.0.1.Finalversion>
    dependency>
    <dependency>
      <groupId>org.jboss.logginggroupId>
      <artifactId>jboss-loggingartifactId>
      <version>3.4.1.Finalversion>
    dependency>

<mvc:annotation-driven>mvc:annotation-driven>

业务页面:

@GetMapping("/register")
public String register(Model model){
    model.addAttribute(new Account());
    return "register";
}

@PostMapping("/register")
public  String register(@Valid Account account,BindingResult bindingResult ){
    if(bindingResult.hasErrors()){
        return "register";
    }else {
        return "success";
    }

}

实体类:

package com.southwind.entity;

import lombok.Data;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@Data
public class Account {
    @NotEmpty(message = "用户名不能为空")
    private  String userName;
    @Size(min = 6,max = 20,message = "长度为5到20位")
    private  String password;
    @Email(regexp = "[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?",message = "请输入正确的表达式")
    private  String email;
    @Pattern(regexp = "\\d{3}-\\d{8}|\\d{4}-\\{7,8}",message = "请输入正确的表达式")
    private String phone;

}

页面:

<%--
  Created by IntelliJ IDEA.
  User: 郝泾钊
  Date: 2022-04-07
  Time: 19:48
  To change this template use File | Settings | File Templates.
--%>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
    <title>Titletitle>
head>
<body>
    <h1> 用户登录h1>
    <form:form modelAttribute="account" action="/validatior/register">
        用户名:<form:input path="userName">form:input><form:errors path="userName">form:errors><br>
        密码:<form:input path="password">form:input><form:errors path="password">form:errors><br>
        邮箱:<form:input path="email">form:input><form:errors path="email">form:errors><br>
        电话:<form:input path="phone">form:input><form:errors path="phone">form:errors><br>
        <input type="submit" value="提交">
    form:form>
body>
html>

spring mvc 的表单标签库

1.Student实体类

package com.southwind.POJO;

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private String gender;
}

2.Handler

package com.southwind.controller;

import com.southwind.POJO.Student;
import com.sun.org.apache.xpath.internal.operations.Mod;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/student")
public class StudenController {
    @GetMapping("/get")
    public String get(Model model){
        Student student =new Student();
        student.setId(1);
        student.setAge(18);
        student.setName("张三");
        student.setGender("男");
        model.addAttribute("student",student);
        return "student";
    }
}

3.JSP

<%--
  Created by IntelliJ IDEA.
  User: 郝泾钊
  Date: 2022-04-07
  Time: 20:53
  To change this template use File | Settings | File Templates.
--%>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
<html>
<head>
    <title>Titletitle>
head>
<body>
    <h1>学生编号h1>
    <form action="" method="post">
        学生编号:<input type="text" value="${student.id}" readonly><br>
        学生姓名:<input type="text" value="${student.name}"><br>
        学生年龄;<input type="text" value="${student.age}"><br>
        学生性别:<input type="text" value="${student.gender}"><br>
        <input type="submit" value="提交">
    form>
body>
html>

表单标签库的使用

1.JSP页面表单标签库的导入

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

2.将form表单的业务数据进行绑定,通过modelAttribute属性完成绑定,将modelAttribute的值设置位控制器象model对象存值是的name即可。

<%--@elvariable id="student" type="com.southwind.POJO.Student"--%>
<form:form  modelAttribute="student" action="/student/update" method="post">
    学生编号:<form:input path="id">form:input><br>
    学生姓名:<form:input path="name">form:input><br>
    学生年龄;<form:input path="age">form:input><br>
    学生性别:<form:input path="gender">form:input><br>
    <input type="submit" value="提交">
form:form>

常用标签的使用

1.from:

<form:form  modelAttribute="student" action="/student/update" method="post">
    form:form>

渲染的是HTML的from标签,通过modelAttribute属性绑定业务数据。

2.input:

<form:input path="name">form:input><br>

渲染的是HTML的input标签,type="text" 绑定的是业务数据中的属性值,与path的业务属性值一样。支持级联

3.password:

<form:password path="age">form:password><br>

渲染的是HTML的password标签,type="text" 绑定的是业务数据中的属性值,与path的业务属性值一样。但是不会在页面现实

4.checkbox:

<form:checkbox path="hobby" value="读书">

form:checkbox>

渲染的是HTML的checkbox标签,type="text" 绑定的是业务数据中的属性值,与path的业务属性值一样。

有Boolean,数组,集合

  • boolean 为true选中 false为不选中。
    student.setFlag(true)

    check:

  • 数组,集合如果和集合中的元素和checkbox相同就选中

5.checkboxs:

<form:checkboxes path="name" items="${student.hobby}">form:checkboxes>

渲染的是一组checkbox标签

item绑定别遍历的数组,path表述选中的数组

student.setHobby(Array.asList("读书","鞋子"))

path可以直接写属性名,item则要通过EL表达式从作用域对象中取值,不能直接写属性名。

6.radiobuttion

<form:radiobutton path="name" value="0">form:radiobutton>

渲染的是一个HTML中的一个单选按钮,值相同为选中状态,值不同为不状态。

7.radiobuttion

<form:radiobuttons path="name" items="${student.name}">form:radiobuttons>

渲染的是html中的一组单选按钮标签

item绑定别遍历的数组,path表述选中的数组

8.select

select path="name" items="${student.name}">select>

渲染的是html中的一组选择标签

item绑定别遍历的数组,path表述选中的数组

9.from:select结合form:optations使用

from:select只定义path form:optations写 items

10.from:select结合form:optation使用

from:select只定义path form:optation写 value

path与哪个valu相等,则默认选择

Springmvc 国际化

在不同的语言设置的浏览器自动显示不同的语言。

1.spring.mvc


    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">

        <property name="basename" value="classpath:language">property>
        <property name="useCodeAsDefaultMessage" value="true">property>
    bean>

    <mvc:interceptors>
        <bean id="localeChangeInterceotor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <property name="paramName" value="Lang">property>
        bean>
    mvc:interceptors>

    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">bean>

2.创建国际化资源文件:

language_en_US.properties

language.cn=\u4E2D\u6587
language.en=English
info=login
userbane=username
password=password
repassword=repassword
tel=tel
email=email
submit=submit
reset=reset

language_en_US.properties

language.cn=\u4E2D\u6587
language.en=English
info=\u767B\u5F55
userbane=\u7528\u6237\u540D
password=\u5BC6\u7801
repassword=\u786E\u8BA4\u5BC6\u7801
tel=\u7535\u8BDD
email=\u7535\u5B50\u90AE\u7BB1
submit=\u63D0\u4EA4
reset=\u91CD\u7F6E

业务页面:

package com.southwind.controller;

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

@Controller
@RequestMapping("/inter")
public class InterHandler {
    @GetMapping("/index")
    public String index(){
        return "inter";
    }
}

相关