RESTful风格的URL,每个网址代表一种资源,其显著的特征就是对于资源的具体操作类型,由HTTP动词表示。SpringMVC 本身是支持 PUT,DELETE 等 HTTP 请求方式的,但由于某些客户端(如:浏览器)并不支持这些,所以 spring 提供了HiddenHttpMethodFilter过滤器来解决这一问题。

员工CRUD操作

首先,配置HiddenHttpMethodFilter,将post请求转为delete或者put请求 。

web.xml文件中配置

<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

其他,一些前期配置这里就不列出来了。所以在搭建一个基本的SpringMVC的基础上再配置上面的内容。

代码编写
  • 目录结构

spring 统一添加url前缀_spring mvc

后端代码
  • 实体类

部门类(Department )

public class Department {

    private Integer id;
    private String departmentName;

    public Department() {
    }

    public Department(int i, String string) {
        this.id = i;
        this.departmentName = string;
    }

    //省略setter/getter
    ......
}

员工类(Employee )

public class Employee {

    private Integer id;
    @NotEmpty
    private String lastName;

    @Email
    private String email;
    //1 male, 0 female
    private Integer gender;

    private Department department;

    @Past
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date birth;

    @NumberFormat(pattern="#,###,###.#")
    private Float salary;

    public Employee(Integer id, String lastName, String email, Integer gender,
            Department department) {
        super();
        this.id = id;
        this.lastName = lastName;
        this.email = email;
        this.gender = gender;
        this.department = department;
    }

    public Employee() {
        // TODO Auto-generated constructor stub
    }

    //省略setter/getter
    ......
}
  • DAO层

这里DAO层不是直接从数据库取数据,为了方便用集合来模拟数据一下数据库。

@Repository
public class DepartmentDao {

    private static Map<Integer, Department> departments = null;

    static{
        departments = new HashMap<Integer, Department>();

        departments.put(101, new Department(101, "D-AA"));
        departments.put(102, new Department(102, "D-BB"));
        departments.put(103, new Department(103, "D-CC"));
        departments.put(104, new Department(104, "D-DD"));
        departments.put(105, new Department(105, "D-EE"));
    }

    public Collection<Department> getDepartments(){
        return departments.values();
    }

    public Department getDepartment(Integer id){
        return departments.get(id);
    }

}

上面是关于部门的数据,接着定义一些员工的数据,指定员工部门。

@Repository
public class EmployeeDao {

    private static Map<Integer, Employee> employees = null;

    @Autowired
    private DepartmentDao departmentDao;

    static{
        employees = new HashMap<Integer, Employee>();

        employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1, new Department(101, "D-AA")));
        employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB")));
        employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC")));
        employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD")));
        employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE")));
    }

    private static Integer initId = 1006;

    public void save(Employee employee){
        if(employee.getId() == null){
            employee.setId(initId++);
        }

        employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
        employees.put(employee.getId(), employee);
    }

    public Collection<Employee> getAll(){
        return employees.values();
    }

    public Employee get(Integer id){
        return employees.get(id);
    }

    public void delete(Integer id){
        employees.remove(id);
    }
}
  • 控制器类
@Controller
public class EmployeeHandler {

    @Autowired
    private EmployeeDao employeeDao;

    @Autowired
    private DepartmentDao departmentDao;

    @ModelAttribute
    public void getEmployee(@RequestParam(value="id",required=false) Integer id,
            Map<String, Object> map){
        if(id != null){
            map.put("employee", employeeDao.get(id));
        }
    }

    @RequestMapping(value="/emp", method=RequestMethod.PUT)
    public String update(Employee employee){
        employeeDao.save(employee);

        return "redirect:/emps";
    }

    @RequestMapping(value="/emp/{id}", method=RequestMethod.GET)
    public String input(@PathVariable("id") Integer id, Map<String, Object> map){
        map.put("employee", employeeDao.get(id));
        map.put("departments", departmentDao.getDepartments());
        return "input";
    }

    @RequestMapping(value="/emp/{id}", method=RequestMethod.DELETE)
    public String delete(@PathVariable("id") Integer id){
        employeeDao.delete(id);
        return "redirect:/emps";
    }

    @RequestMapping(value="/emp", method=RequestMethod.POST)
    public String save(@Valid Employee employee, Errors result, 
            Map<String, Object> map){
        System.out.println("save: " + employee);

        if(result.getErrorCount() > 0){
            System.out.println("出错了�!");

            for(FieldError error:result.getFieldErrors()){
                System.out.println(error.getField() + ":" + error.getDefaultMessage());
            }

            //若页面出错,则跳转到指定页面
            map.put("departments", departmentDao.getDepartments());
            return "input";
        }

        employeeDao.save(employee);
        return "redirect:/emps";
    }

    @RequestMapping(value="/emp", method=RequestMethod.GET)
    public String input(Map<String, Object> map){
        map.put("departments", departmentDao.getDepartments());
        map.put("employee", new Employee());
        return "input";
    }

    @RequestMapping("/emps")
    public String list(Map<String, Object> map){
        map.put("employees", employeeDao.getAll());
        return "list";
    }

//  @InitBinder
//  public void initBinder(WebDataBinder binder){
//      binder.setDisallowedFields("lastName");
//  }

}
前端页面
  • 列表页面(list.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!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>
<!--  
    SpringMVC 处理静态资源:
    1. 为什么会有这样的问题:
    优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀
    若将 DispatcherServlet 请求映射配置为 /, 则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。
    2. 解决: 在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/>
-->
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
    $(function(){
        $(".delete").click(function(){
            var href = $(this).attr("href");
            $("form").attr("action", href).submit();           
            return false;
        });
    })
</script>
</head>
<body>

    <form action="" method="POST">
        <input type="hidden" name="_method" value="DELETE"/>
    </form>

    <c:if test="${empty requestScope.employees }">
        没有任何员工信息.
    </c:if>
    <c:if test="${!empty requestScope.employees }">
        <table border="1" cellpadding="10" cellspacing="0">
            <tr>
                <th>ID</th>
                <th>LastName</th>
                <th>Email</th>
                <th>Gender</th>
                <th>Department</th>
                <th>Edit</th>
                <th>Delete</th>
            </tr>

            <c:forEach items="${requestScope.employees }" var="emp">
                <tr>
                    <td>${emp.id }</td>
                    <td>${emp.lastName }</td>
                    <td>${emp.email }</td>
                    <td>${emp.gender == 0 ? 'Female' : 'Male' }</td>
                    <td>${emp.department.departmentName }</td>
                    <td><a href="emp/${emp.id}">Edit</a></td>
                    <td><a class="delete" href="emp/${emp.id}">Delete</a></td>
                </tr>
            </c:forEach>
        </table>
    </c:if>

    <br><br>

    <a href="emp">Add New Employee</a>

</body>
</html>
  • input.jsp
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!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>

    <form action="testConversionServiceConverer" method="POST">
        <!-- lastname-email-gender-department.id 例如: GG-gg@atguigu.com-0-105 -->
        Employee: <input type="text" name="employee"/>
        <input type="submit" value="Submit"/>
    </form>
    <br><br>

    <!--  
        1. WHY 使用 form 标签呢 ?
        可以更快速的开发出表单页面, 而且可以更方便的进行表单值的回显
        2. 注意:
        可以通过 modelAttribute 属性指定绑定的模型属性,
        若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean
        如果该属性值也不存在,则会发生错误。
    -->
    <br><br>
    <form:form action="${pageContext.request.contextPath }/emp" method="POST" 
        modelAttribute="employee">

        <form:errors path="*"></form:errors>
        <br>

        <c:if test="${employee.id == null }">
            <!-- path 属性对应 html 表单标签的 name 属性值 -->
            LastName: <form:input path="lastName"/>
            <form:errors path="lastName"></form:errors>
        </c:if>
        <c:if test="${employee.id != null }">
            <form:hidden path="id"/>
            <input type="hidden" name="_method" value="PUT"/>
            <%-- 对于 _method 不能使用 form:hidden 标签, 因为 modelAttribute 对应的 bean 中没有 _method 这个属性 --%>
            <%-- 
            <form:hidden path="_method" value="PUT"/>
            --%>
        </c:if>

        <br>
        Email: <form:input path="email"/>
        <form:errors path="email"></form:errors>
        <br>
        <% 
            Map<String, String> genders = new HashMap();
            genders.put("1", "Male");
            genders.put("0", "Female");

            request.setAttribute("genders", genders);
        %>
        Gender: 
        <br>
        <form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/>
        <br>
        Department: <form:select path="department.id" 
            items="${departments }" itemLabel="departmentName" itemValue="id"></form:select>
        <br>
        <!--  
            1. 数据类型转换
            2. 数据类型格式化
            3. 数据校验. 
            1). 如何校验 ? 注解 ?
            ①. 使用 JSR 303 验证标准
            ②. 加入 hibernate validator 验证框架的 jar 包
            ③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />
            ④. 需要在 bean 的属性上添加对应的注解
            ⑤. 在目标方法 bean 类型的前面添加 @Valid 注解
            2). 验证出错转向到哪一个页面 ?
            注意: 需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参
            3). 错误消息 ? 如何显示, 如何把错误消息进行国际化
        -->
        Birth: <form:input path="birth"/>
        <form:errors path="birth"></form:errors>
        <br>
        Salary: <form:input path="salary"/>
        <br>
        <input type="submit" value="Submit"/>
    </form:form>

</body>
</html>

至此,我们完成了对员工增删查改的所有功能。以上内容主要参考尚硅谷教程。

集成Swagger2

1、在pom.xml文件中添加如下jar包。

<dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.2.2</version>
    </dependency>
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.2.2</version>
    </dependency>
    <!-- swagger2需要jackson -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.5.4</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.5.4</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.5.4</version>
    </dependency>
  </dependencies>

2、Swagger2配置

@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket addUserDocket(){
        Docket docket = new Docket(DocumentationType.SWAGGER_2);
        ApiInfo apiInfo = new ApiInfo("restful API", "API Document","V1.0", "www.baidu.com", "我的邮箱", "", "");
        docket.apiInfo(apiInfo);
        return docket;
    }
}

3、在spring-mvc.xml文件中配置

<bean name="swaggerConfig" class="org.chm.swagger.SwaggerConfig"/>
    <!--<bean class="springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration" id="swagger2Config"/>--> <!-- swagger默认配置 -->
    <mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
    <mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>

4、在Controller类中上添加@Api注解,用于描述接着类。

@Api(value = "员工类",tags = "员工增删查改")
@Controller
public class EmployeeHandler

下面是一些Swagger中常见的注解:

1、swagger类注释
@Api(value = “订单类”,tags = “订单类测试接口”)

swagger接口注释
@ApiOperation(“订单列表”)

swagger参数注释
@ApiParam(“订单ID”)

2、swagger实体类注释
@ApiModel(“订单实体类”)

swagger实体类中隐藏属性
@ApiModelProperty(hidden = true)

swagger实体属性备注
@ApiModelProperty(“订单编号”)

Swagger2默认将所有的Controller中的RequestMapping方法都会暴露, 然而在实际开发中,我们并不一定需要把所有API都提现在文档中查看,这种情况下,使用注解@ApiIgnore来解决。

最后,在浏览器中输入http://localhost:8080/swagger-ui.html。即可看到我们的成果了。

spring 统一添加url前缀_spring 统一添加url前缀_02