SpringMVC笔记五: Restful_CRUD

这篇文章介绍如何使用SpringMVC实现简单的、REST风格的员工信息的增删改查操作。
Employee.java:

package com.springmvc.crud.entities;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;

import java.util.Date;

public class Employee {

    private Integer id;

    private String lastName;


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

    private Department department;

    //其它方法略
    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

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

Department.java:

package com.springmvc.crud.entities;

public class Department {

    private Integer id;
    private String departmentName;

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

    public Department(int i, String string) {
        this.id = i;
        this.departmentName = string;
    }
    //其它方法略

}

DAO层是模拟从数据库中获取信息的,员工信息,宿舍详细信息存在这里:
EmployeeDao.java:

@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++);
        }
        //传过来的department对象的departmentName属性为空,所以要重新生成department对象
        Department department=departmentDao.getDepartment(employee.getDepartment().getId());
        employee.setDepartment(department);
        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);
    }
}

DepartmentDao.java:

@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);
    }

}

这里,我们还需要MVC中的Controller类EmployeeHandler,我们先看看它的字段,

    @Autowired
    private EmployeeDao employeeDao;

    @Autowired
    private DepartmentDao departmentDao;

有两个DAO层的对象,通过这两个对象我们来获取数据库的信息。

CRUD

①查看所有员工的信息:
我认为所有的增删改查都是数据流向的问题,比如此处的员工信息存储在DAO层的EmployeeDao中,要查看员工信息的话,就只需要把DAO层的数据想办法传到View层。所以在Handler中我们可以这样处理:

    @RequestMapping("/emps")
    public  String list(Map<String,Object> map){
    //把employee的collection传给model的属性,跳转到list.jsp
        map.put("employees",employeeDao.getAll());
        return "list";
    }

因为传到view层的是一个list,所以要用循环把值取出来,可以在list.jsp中加上

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:if test="${empty requestScope.employees}">
    没有任何员工信息.
</c:if>
<c:if test="${!empty requestScope.employees}">
    <table border="1" cellspacing="10" cellpadding="10">
        <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="deleteInfo" href="emp/${emp.id}">delete</a> </td>
            </tr>
        </c:forEach>
    </table>
</c:if>
<br><br>

这样所有的员工信息就显示了,在显示员工信息的页面上,我们需要增加一个添加员工的请求。
②增加:
在list.jsp的body标签部分增加:

<a href="emp">添加员工信息</a>

这是一个简单的GET请求,我们要在Controller中处理这个请求:

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

这个处理方法会将目前DAO层的员工信息和宿舍信息添加到model属性里,然后转到input.jsp。

这里使用了SpringMVC 的form的表单标签,可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显。form的属性(path值)和modelAttribute 属性绑定的Bean属性相对应。若没有指定modelAttribute属性,则默认从request 域对象中读取command的表单bean。

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form action="${pageContext.request.contextPath }/emp" method="POST"
           modelAttribute="employee">

    LastName: <form:input path="lastName"/>
    Email:<form:input path="email" /><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>
    <!--form:select:用于构造下拉框组件,items="${departments}"代表下拉组件的值由model属性departments决定,显示在页面上的是itemLabel(此处为宿舍名),提交表单时传递的是itemValue(id号) -->
    Department:<form:select path="department.id" items="${departments}"
                            itemLabel="departmentName" itemValue="id"/><br>
    <input type="submit" value="submit"/>

提交的表单会转移到Controller目录下(action的url):

    @RequestMapping(value = "/emp" ,method = RequestMethod.POST)
    public String saveEmployeeInfo(Employee employee){
        employeeDao.save(employee);
        return "redirect:/emps";
    }

保存之后再重定向到emps,让对应的处理方法去处理。

③删除:
 在list.jsp页面,点击delete是一个get请求,最终要把它转化成delete请求,我们知道get请求不能直接转化成delete请求,必须先转化成post请求,再借助隐藏域用HiddenHttpMethodFilter把post请求转化成delete请求。那我点击一个get请求,是怎样变成post请求的呢?这里我们要借助JavaScript。
 

<td><a class="deleteInfo" href="emp/${emp.id}"> delete </a> </td>

点击delete后,js函数会以表单的方式提交请求,而这个请求是包含了type=”hidden”的。

<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
    $(function(){
        $(".deleteInfo").click(function(){//.代表所有后缀是deleteInfo的,相当于通配符
            var href = $(this).attr("href");
            $("form").attr("action", href).submit();//只有一个form,将变量href传给form的action属性,然后提交post请求
            return false;
        });
    })
</script>
<form action="" method="POST">
    <input type="hidden" name="_method" value="DELETE"/>
</form>

当然直接使用上述的导入js文件的办法的话,会报no mapping found for http request with url……的error。这是因为SpringMVC 中,若你把 DispatcherServlet 请求映射配置为 /, 则 Spring MVC 将捕获 WEB 容器的所有请求。

 http://localhost:8080/SpringMVC02/scripts/jquery-1.9.1.min.js

pass:静态资源:如图片,js,CSS
这是你需要的静态资源的请求(本来此处不需要url映射的),但SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。 优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀,就需要在SpringMVC的配置文件中添加配置:

 <mvc:default-servlet-handler />
 <mvc:annotation-driven></mvc:annotation-driven>

其原理是:default-servlet-handler 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求, 就将该请求交由 WEB 应用服务器默认的 Servlet 处理。如果不是静态资源的请求,才由 DispatcherServlet 继续处理。一般情况下,WEB 应用服务器默认的 Servlet 的名称都是 default。若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定。
这样,在Controller中:

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

④修改:(LastName字段不可修改,要求能够回显表单,更新后重定向到显示员工信息页面.)

    <td><a href="emp/${emp.id}">edit</a> </td>
    @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";
    }

注意这里传到input.jsp的DAO层数据和增加操作相比,多了一个员工的id号,根据id是否为空(不为空是edit操作,须隐藏name,并用隐藏域的方法将表单提交请求改成PUT):

    <c:if test="${employee.id == null }">
        LastName: <form:input path="lastName"/> <!-- path 属性对应 html 表单标签的 name 属性值 -->
        <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"/>
    </c:if>

最后放一下配置文件:
web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--配置HiddenHttpMethodFilter,可以从post请求转换成put,delete请求-->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--MVC配置文件的位置和名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

springmvc.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--配置自动扫描的包,自动扫描包及其子包下的类,带注解如@Controller的,
    满足指定url(通过RequestMapping)类中方法返回一个逻辑视图-->
    <context:component-scan base-package="com.springmvc.crud"></context:component-scan>

    <!--配置视图解析器:如何把请求处理类中方法返回的值解析为实际的物理视图 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/</value>
        </property>

        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <mvc:default-servlet-handler />
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值