基于spring4
RESTRUL_CRUD_需求(非常重要)
给的工具集:为了方便说明,我们不使用数据库,也不使用aop的事务,用现成的javabean类和dao工具类,里面有数据和具体的增删改查方法。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.atguigu.bean; public class Employee { private Integer id; private String lastName; private String email; //1 male, 0 female private Integer gender; private Department department; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getGender() { return gender; } public void setGender(Integer gender) { this.gender = gender; } 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() { } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + ", department=" + department + "]"; } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.atguigu.bean; public class Department { private Integer id; private String departmentName; public Department() { } public Department(int i, String string) { this.id = i; this.departmentName = string; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getDepartmentName() { return departmentName; } public void setDepartmentName(String departmentName) { this.departmentName = departmentName; } @Override public String toString() { return "Department [id=" + id + ", departmentName=" + departmentName + "]"; } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.atguigu.dao; import com.atguigu.bean.Department; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.HashMap; import java.util.Map; @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(); } //按部门id查一个 public Department getDepartment(Integer id){ return departments.get(id); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.atguigu.dao; import com.atguigu.bean.Department; import com.atguigu.bean.Employee; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.HashMap; import java.util.Map; @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++); } //根据部门id单独查出部门信息设置到员工对象中,页面提交只需要提交部门的id 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); } }
项目要求:
.
第一步:构建一个框架,先导包,蓝色部分的是第一步导的,剩下那两个等下再导。
1.————
2.————配置web.xml文件。
1)配置前端控制器 DispatcherServlet。
2)配置拦截器字符集,utf-8。
3)配置 HiddenHttpMethodFilter 把 post 请求转为 delete 或 put 请求。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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_4_0.xsd" version="4.0"> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--配置字符集,拦截器一定在前--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--配置org.springframework.web.filter.HiddenHttpMethodFilter:可以把 post 请求转为 delete 或 put 请求--> <!--导包servlet-api.jar--> <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> </web-app>
3.————由于我没有给DispatcherServlet设置初始化值,所以会自动配置到 "<NAME> - servlet.xml"这个文件里。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--配置自动扫描的包--> <context:component-scan base-package="com.atguigu"> </context:component-scan> <!--配置视图解析器:如何把handler方法返回值(本例中就是"success")解析为实际的物理视图--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"> </property> <property name="suffix" value=".jsp"> </property> </bean> </beans>
4.————写test包进行测试。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.atguigu.test; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * Created by Zhuxiang on 2020/6/2. */ @Controller public class hello2 { @RequestMapping("/hello") public String hello(){ System.out.println("hellon world"); return "success"; } }
去加上一个 <a href="/springMVC(web项目名)/hello">hello</a>
写上views里的success.jsp
success.jsp里加上success page这行字。
5.————配置tomcat服务器,启动服务器,进入index.jsp页面后点击a标签
成功进入success页面。测试框架完成。
下图为工程全貌图,可以帮助大家理解步骤。
第二步:显示所有员工信息
1————index.jsp页面里(在html标签外面)加上<jsp:forward page="/emps"></jsp:forward>转发到控制层,获得所有员工信息。
2————
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Controller public class EmployeeControl { @Autowired EmployeeDao employeeDao; @RequestMapping("emps") public String getEmps(Model model){ Collection<Employee> all = employeeDao.getAll(); model.addAttribute("emps",all); return "list"; } }
3————return到list页面。这个时候需要导包
循环获得数据需要用 c 标签里的 c:forEach。
而springmvc也提供了一个form标签,用来简化表单。
(下面代码还写了增,删,改。但目前先看查的部分)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <body> <h1>员工列表</h1> <table border="1" cellpadding="5" 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="${emps}" var="emp"> <tr> <td>${emp.id}</td> <td>${emp.lastName}</td> <td>${emp.email}</td> <td>${emp.gender==0?"女":"男"}</td> <td>${emp.department.departmentName}</td> <td>Edit</td> <td> delete </td> </tr> </c:forEach> </table> <a href="">添加</a>
启动tomcat,页面上出现
第三步:添加员工信息
1————点击添加。转发到 'toAddEmp' 方法里,看需求不难发现,部门选择下拉框的值是动态生成的。我们还没学到ajax之前,可以先用老办法,直接查出所有下拉框的值,保存到请求域中,传到 save 页面里。
加上下面的代码,自动装配。
@Autowired
DepartmentDao departmentDao;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@RequestMapping("toAddEmp") public String toAddPage(Model model){ Collection<Department> departments = departmentDao.getDepartments(); model.addAttribute("deps",departments); //把command放到请求域中。 // model.addAttribute("command",new Employee(null,"张三","haha@guigu.com",0,departmentDao.getDepartment(101))); //因为form标签给command改了个名字,所以这么放。 model.addAttribute("employee",new Employee()); return "save"; }
2————开始编写 save.jsp
要点:
1.springmvc提供的form标签。
2.请求域中的固定对象 command
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2020/6/3 Time: 7:15 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" %> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <html> <head> <title>save</title> </head> <body> <%--springMVC的表单标签 通过springMVC的表单标签可以实现将模型数据中的属性和html表单元素相绑定 以实现表单数据更便捷的编辑和表单值的回显 1)springmvc认为,表单数据中的每一项最终都是要回显的。 path指定的是一个属性;这个属性是从隐含模型(请求域中取出的某个对象中的属性) path指定的每一个属性,请求域中必须有一个对象,拥有这个属性; 所以单纯像下面这样写,跑起来就报错了, 因为请求域里缺少一个对象,这个对象就是请求域中的command, 由于command是固定名字,不好听,所以我们可以重新命名。用form的modelAttribute属性。 --%> <!--记得导包jsp-api,action里推荐写绝对路径,下面是获得项目路径的代码--> <% request.setAttribute("project",request.getContextPath()); %> <form:form action="${project}/emp" method="post" modelAttribute="employee"> <!-- path就是原来html-input的name项,需要写path, 1)当做原生的name项 2)自动回显隐含模型中某个对象对应的这个属性的值 --> LastName:<form:input path="lastName"/><br/> Email:<form:input path="email"/><br/> gender: <form:radiobutton path="gender" value="1"/>男 <form:radiobutton path="gender" value="0"/>女 <!-- items指定要遍历的集合:自动遍历,遍历出的每一个元素是一个department对象 itemLabel="属性";指定遍历出的这个对象的哪个属性是作为option标签体的值 itemValue="属性";指定遍历出的这个对象的哪个属性是作为option提交的值 --> dept:<form:select path="department.id" items="${deps}" itemLabel="departmentName" itemValue="id"/> <input type="submit" value="提交"> </form:form> <%--<form action="${project}/emp" method="post" modelAttribute="employee">--%> <%-- LastName:<input type="text" name="lastName">--%> <%-- <br/>--%> <%-- Email:<input type="text" name="email">--%> <%-- <br/>--%> <%-- Gender:<input type="radio" name="gender" value="1">Male--%> <%-- <input type="radio" name="gender" value="0">Female--%> <%-- <br/>--%> <%-- Department:--%> <%-- <select name="department.id">--%> <%-- <c:forEach items="${deps}" var="dept">--%> <%-- <option value="${dept.id}">${dept.departmentName}</option>--%> <%-- </c:forEach>--%> <%-- </select>--%> <%-- <br/>--%> <%-- <input type="submit" value="提交">--%> <%--</form>--%> </body> </html>
3————输入信息,点击提交。进入emp映射,为了满足 restful 风格,映射里加上,增加的,method = RequestMethod.POST
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@RequestMapping(value = "emp",method = RequestMethod.POST)
public String addEmp(Employee employee){
System.out.println("要添加的员工"+employee);
employeeDao.save(employee);
//返回列表页面,重定向到查询所有员工的请求
return "redirect:/emps";
}
第四步:修改员工信息
1————在list页面里点击修改,查询员工再到修改页面 edit.jsp里,(用 rest 风格发送参数,如:emp/${emp.id})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//查询员工来到修改页面 @RequestMapping(value = "/emp/{id}",method = RequestMethod.GET) public String getEmp(@PathVariable("id") Integer id,Model model){ Employee employee = employeeDao.get(id); model.addAttribute("employee",employee); Collection<Department> departments = departmentDao.getDepartments(); model.addAttribute("departments",departments); return "edit"; }
2————编写edit.jsp
要点:
1. rest风格,'修改' 为put 。表单必须加上<input type="hidden" name="_method" value="put">。
2.留下id的隐藏域。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2020/6/3 Time: 16:19 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>Title</title> </head> <body> <% request.setAttribute("ctp",request.getContextPath()); %> <form:form action="${ctp}/emp/${employee.id}" method="post" modelAttribute="employee"> <input type="hidden" name="_method" value="put"> <!--如果不加id发送,id的值就是null,最好加上id--> <!--但是隐藏域不够安全,浏览器f12加检查元素可以修改,所以lastName就不用隐藏域了--> <form:hidden path="id"/> Email:<form:input path="email"/><br/> gender: <form:radiobutton path="gender" value="1"/>男 <form:radiobutton path="gender" value="0"/>女 dept:<form:select path="department.id" items="${departments}" itemLabel="departmentName" itemValue="id"/> <input type="submit" value="提交"> </form:form> </body> </html>
3————用 rest 风格接收参数 value = "/emp/{id}",method = RequestMethod.PUT
要点:
1. 根据题目要求,lastname不允许被修改,但是表单提交又需要它。重要数据最好不要用隐藏域。
用上@ModelAttribute注解,在每个方法执行之前根据 id 查出employee。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@ModelAttribute
public void myModelAttribute(@RequestParam(value = "id",required = false) Integer id,Model model){
if(id!=null){
Employee employee = employeeDao.get(id);
model.addAttribute("employee",employee);
}
}
//修改员工并重定向到emps
@RequestMapping(value = "/emp/{id}",method = RequestMethod.PUT)
//不用edit.jsp隐藏域 也可以用这种方式获得id
// 入参加上@PathVariable("id")Integer id会自动装配。
public String updateEmp(Employee employee){
System.out.println("update"+employee);
//但是隐藏域不够安全,浏览器f12加检查元素可以修改,所以lastName就不用隐藏域了
employeeDao.save(employee);
return "redirect:/emps";
}
第五步:删除员工信息
1————在list页面里点击删除,通过删除方法后,返回到emps里,(用 rest 风格发送参数,如:emp/${emp.id})
问题:
1,删除是一个a标签,但是按restful风格,必须要post提交一个 name="_method" value="delete" 的组件。怎么办?
一,把a标签改成form表单。效果达到了,但是页面变得丑陋,代码臃肿。
二,引入jQuery。点a标签,1.改变表单的action指向 2.提交表单
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@RequestMapping(value = "/emp/{id}",method = RequestMethod.DELETE) public String deleteEmp(@PathVariable("id")Integer id){ employeeDao.delete(id); return "redirect:/emps"; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2020/6/2 Time: 22:20 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" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <% request.setAttribute("ctp",request.getContextPath()); %> <html> <head> <title>员工列表</title> <!--为了不让delete方法丑陋,加入jQuery --> <script type="text/javascript" src="${ctp}/scripts/jquery-1.9.1.min.js"></script> </head> <body> <h1>员工列表</h1> <table border="1" cellpadding="5" 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="${emps}" var="emp"> <tr> <td>${emp.id}</td> <td>${emp.lastName}</td> <td>${emp.email}</td> <td>${emp.gender==0?"女":"男"}</td> <td>${emp.department.departmentName}</td> <td><a href="${ctp}/emp/${emp.id}">Edit</a></td> <td> <a href="${ctp}/emp/${emp.id}" class="delBtn">delete</a> </td> </tr> </c:forEach> </table> <a href="${ctp}/toAddEmp">添加</a> <form:form id="deleteForm" action="${ctp}/emp/${emp.id}" method="post"> <input type="hidden" name="_method" value="delete"> </form:form> <!--jQuery默认被servlet的拦截器拦截,说ioc没有对应,所以404。 让它被tomcat拦截就行了 dispatcher-servlet.xml加上映射处理--> <script type="text/javascript"> $(function () { alert("haha"); $(".delBtn").click(function () { //1.改变表单的action指向 $("#deleteForm").attr("action", this.href); //2.提交表单 $("#deleteForm").submit(); return false; }) }) </script> </body> </html>
三,静态资源,动态资源访问问题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!--jQuery默认被servlet的拦截器拦截,说ioc没有对应,所以404。 让它被tomcat拦截就行了--> <!--告诉springMVC,不能处理的映射给tomcat处理--> <!-- 方法一(不推荐):web里的DispatcherServlet里加上下面的4行就行。--> <!-- <servlet-mapping>--> <!-- <servlet-name>default</servlet-name>--> <!-- <url-pattern>*.js</url-pattern>--> <!-- </servlet-mapping>--> <!--方法二:(推荐) default是默认的服务器拦截,不要像一个憨逼一样,把自己配的servlet命名成default--> <mvc:default-servlet-handler/> <!--静态资源可以访问,但是动态映射的请求就不行(访问list 404)--> <!--springMVC保证动态请求和静态请求都能访问--> <mvc:annotation-driven/>