SpringMVC——RestFul风格的CRUD
一、基础配置
1、由于要使用RestFul风格的提交方式,所以要配置HiddenHttpMethodFilter,将post请求转变为DELETE或者PUT
<!-- 转换请求方式的配置 -->
<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>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2、springDispatcherServlet-servlet.xml的配置
<!-- 自动扫面的包 -->
<context:component-scan base-package="com.bdm.springmvc"/>
<!-- 视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 由于要引入jQuery等外部文件,必须有此配置,否则springmvc的视图解析器会将外部文件的引入当成对服务器资源的访问 -->
<mvc:default-servlet-handler/>
<!-- 有了mvc:default-servlet-handler就必须要有这个配置 -->
<mvc:annotation-driven/>
二、增删改查
1、查询
前端:index.jsp
<a href="${pageContext.request.contextPath }/emps">Show Employee List</a>
后台方法:
@RequestMapping(value = "/emps", method = RequestMethod.GET)
public String listEmps(Map<String, Object> map) {
map.put("employees", empDao.getAll());
return "list";
}
结果页面:list.jsp
<c:if test="${requestScope.employees == null }">
<h2>NOTHING TO SHOW</h2>
</c:if>
<c:if test="${requestScope.employees != null }">
<table>
<tr>
<th>ID</th>
<th>LastName</th>
<th>Email</th>
<th>Gender</th>
<th>Dept</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 == '1' ? '男' : '女' }</td>
<td>${emp.department.departmentName }</td>
<td>
<a href="${pageContext.request.contextPath }/emps/${emp.id}">Edit</a>
</td>
<td>
<a class="delA" href="${pageContext.request.contextPath }/emps/${emp.id}">Del</a>
<!-- 这个表单是将delete的get请求转变为DELETE请求需要的 -->
<form class="delForm" action="${pageContext.request.contextPath }/emps/${emp.id}" method="post">
<input type="hidden" name="_method" value="delete"/>
</form>
</td>
</tr>
</c:forEach>
</table>
<br/>
<a href="${pageContext.request.contextPath }/emp">ADD</a>
</c:if>
2、添加
前台:list.jsp
<a href="${pageContext.request.contextPath }/emp">ADD</a>
后台:点击添加后先转到一个信息填写的表单页面
@RequestMapping(value = "/emp")
public String input(Map<String, Object> map) {
// 准备回显的数据
map.put("depts", deptDao.getDepartments());
map.put("genders", getGenders());
map.put("employee", new Employee());
return "input";
}
表单填写页面:input.jsp
<form:form action="${pageContext.request.contextPath }/emps" modelAttribute="employee" method="post">
Name:<form:input path="lastName"/><br/><br/>
Email:<form:input path="email"/><br/><br/>
Gender:<form:radiobuttons path="gender" items="${genders }"/><br/><br/>
Depts:<form:select path="department.id" items="${depts }" itemLabel="departmentName" itemValue="id"/><br/><br/>
<input type="submit" value="提交">
</form:form>
表单填好后的处理:
@RequestMapping(value = "/emps", method = RequestMethod.POST)
public String addEmp(Employee employee) {
empDao.save(employee);
//重定向到列表页
return "redirect:emps";
}
3、修改
请求超链接:
<a href="${pageContext.request.contextPath }/emps/${emp.id}">Edit</a>
进入修改信息的表单:此处使用了PathVariable风格的url,可以轻松的获取到传递的id
@RequestMapping(value = "/emps/{empId}")
public String edit(@PathVariable("empId") Integer id, Map<String, Object> map) {
map.put("genders", getGenders());
map.put("depts", deptDao.getDepartments());
map.put("employee", empDao.get(id));
return "edit";
}
表单中有个隐藏域保存id的值,还有一个_method隐藏域:
<form:form action="${pageContext.request.contextPath }/emps" modelAttribute="employee" method="post">
<input type="hidden" name="id" value="${employee.id }"/>
<input type="hidden" name="_method" value="put"/>
Name:<form:input path="lastName"/><br/><br/>
Email:<form:input path="email"/><br/><br/>
Gender:<form:radiobuttons path="gender" items="${genders }"/><br/><br/>
Depts:<form:select path="department.id" items="${depts }" itemLabel="departmentName" itemValue="id"/><br/><br/>
<input type="submit" value="提交">
</form:form>
请求的处理:对于修改和删除都需要先根据id到数据库查询要修改或删出的对象,要先调用@ModelAttribute注解的方法,将对象置于隐含域中
@ModelAttribute
public void getEmpById(@RequestParam(value = "id", required = false) Integer id, Map<String, Object> map) {
if (id != null) {
Employee emp = empDao.get(id);
map.put("employee", emp);
}
}
调用完有@ModelAttribute注解的方法后再调用修改的方法:方法和添加很像,只不过method有添加的post变为修改的put
@RequestMapping(value = "/emps", method = RequestMethod.PUT)
public String putEdit(Employee employee) {
empDao.save(employee);
return "redirect:emps";
}
4、删除
使用jquery先使原来的删除超链接失效,再让其发送DELETE方式的请求,需要一个提交方式是DELETE的表单辅助
<script type="text/javascript">
$(function(){
$(".delA").click(function(){
var flag = confirm("你真的要删除这个员工的信息吗?");
if(flag){
$(".delForm").submit();
}
return false;
});
})
</script>
<a class="delA" href="${pageContext.request.contextPath }/emps/${emp.id}">Del</a>
<!-- 这个表单是将delete的get请求转变为DELETE请求需要的 -->
<form class="delForm" action="${pageContext.request.contextPath }/emps/${emp.id}" method="post">
<input type="hidden" name="_method" value="delete"/>
</form>
后台的删除操作:会先调用@ModelAttribute注解的getEmpById()方法将对象置于隐含域中
@RequestMapping(value = "/emps/{empId}", method = RequestMethod.DELETE)
public String delete(@PathVariable("empId") Integer id) {
empDao.delete(id);
return "redirect:/emps";
}
三、总结
1、流程简易分析
①添加:点击超链接->进入handler,准备需在表单中显示的数据(性别、部门、表单中添加时接收参数的对象:不要以为添加时不需要一个对象,因为表单中使用了form:form的modelAttribute属性,该属性的值即是此处置于隐含域中的对象的key,然后表单中的path都指向该对象的属性)->填写好表单后提交到后台调用dao的save方法完成保存,看下表单
<form:form action="${pageContext.request.contextPath }/emps" modelAttribute="employee" method="post">
Name:<form:input path="lastName"/><br/><br/>
Email:<form:input path="email"/><br/><br/>
Gender:<form:radiobuttons path="gender" items="${genders }"/><br/><br/>
Depts:<form:select path="department.id" items="${depts }" itemLabel="departmentName" itemValue="id"/><br/><br/>
<input type="submit" value="提交">
</form:form>
②修改和删除:修改和删除的操作执行之前会调用@ModelAttribute注解的方法(实际上只要Handler中有@ModelAttribute注解的方法,则所有请求处理方法都会调用使用@ModelAttribute注解的方法),将要操作的对象根据id查找出来并置于隐含域中(该隐含域的功能有点类似于struts2中的值栈),修改可以先点击超链接进入到一个修改的表单中,将表单的提交方式修改为PUT即可,而对于删除,由于没有一个表单使其发送DELETE方式的请求,所以需要借助于jQuery使原来的超链接失效,转而发送一个表单的DELETE请求(需要一个表单辅助)
③查询:略
2、注意点:
①、RestFul风格的请求方式不仅可以根据请求的url区别,还可以根据请求的方式(get、post、put、delete)区别
②在引入了外部文件时,必须在springmvc的ioc容器中做如下配置:
<!-- 由于要引入jQuery等外部文件,必须有此配置,否则springmvc的视图解析器会将外部文件的引入当成对服务器资源的访问 -->
<mvc:default-servlet-handler/>
<!-- 有了mvc:default-servlet-handler就必须要有这个配置 -->
<mvc:annotation-driven/>
③在重定向的时候,有时不加/也可以,但是最好加上:return “redirect:/emps”;
Tip
:表单中的modleAttribute属性的值并不是随便取的,也不是类名的首字母小写,而是从隐含域中取得的,在进去input.jsp或者edit.jsp等有表单的页面之前,都会调用一个方法,在该方法中会往隐含域中放一个对象用以接收请求参数和回显数据,表单中的modleAttribute属性的值就是此时放入Map或其他隐含域中的键的值,也就是说它只是一个名字而已,必须和放入到隐含域中的对象名一致,否则就会出错。其中的path属性是modleAttribute中的对象的属性名,相当于从这个对象中获取数据,有则回显,没有则不回显。