1、准备工作
和传统 CRUD 一样,实现对员工信息的增删改查。
搭建环境
准备实体类
package com.atguigu.mvc.bean;
public class Employee {
private Integer id;
private String lastName;
private String email;
//1 male, 0 female
private Integer gender;
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 Employee(Integer id, String lastName, String email, Integer gender) {
super();
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
}
public Employee() {
}
}
准备dao模拟数据
package com.atguigu.mvc.dao;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.atguigu.mvc.bean.Employee;
import org.springframework.stereotype.Repository;
@Repository
public class EmployeeDao {
private static Map<Integer, Employee> employees = null;
static{
employees = new HashMap<Integer, Employee>();
employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
}
private static Integer initId = 1006;
public void save(Employee employee){
if(employee.getId() == null){
employee.setId(initId++);
}
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);
}
}
2、功能清单
功能 | URL 地址 | 请求方式 |
---|---|---|
访问首页√ | / | GET |
查询全部数据√ | /employee | GET |
删除√ | /employee/2 | DELETE |
跳转到添加数据页面√ | /toAdd | GET |
执行保存√ | /employee | POST |
跳转到更新数据页面√ | /employee/2 | GET |
执行更新√ | /employee | PUT |
1、访问所有员工数据的页面实现
在首页里面写了一个查看员工信息的超链接,若想实现查看员工信息这个功能,我们该怎么办?
不能直接访问我们的员工列表页面,就需要用异步请求了,没有用AJAX,首先必须通过控制器的处理这个请求,查询出来数据,放在域对象中,在跳转到页面才能够看到数据。
要想去展示当前的员工信息,最好是用一个表格,html中最常用的两个标签,一个是表单,一个是表格, 表格用来展示数据,表单用来展示数据。
<th>是表头,能够自动加粗并居中。
<table border="1" cellspacing="0" cellpadding="0" style="text-align: center;">
<tr>
<!--合并列为5-->
<th colspan="5">Employee Info</th>
</tr>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>options</th>
</tr>
<!--each这里是代表我们要遍历的每一个数据,因为我们的数据是在请求域中去放的,所以我们要用${}去访问-->
<tr th:each="employee : ${employeeList}">
<!--不能直接在td里面${employee.id},因为我们当前在td标签里面去写的话,会被当成文本原样解析
所以要想操作文本内容,应该用th:text
-->
<td th:text="${employee.id}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<td th:text="${employee.gender}"></td>
<td>
<a href="@{/employee}+${employee.id}">delete</a>
<a href="">update</a>
</td>
</tr>
</table>
1、${employee.id}这个值要想解析需要通过+拼接的形式,不能放在@{}里面,在@{}里面是解析成路径。
2、要想放在@{}里面,前面表示请求地址的/employee/要加上单引号' ',在里面用+号,此时${}里面会解析成数据
2、删除功能的实现
超链接只能发送get请求,要想发送delete请求,需要借助我们的过滤器,过滤器要求我们的表单必须有method=post,请求参数_method=delete。
此时是通过vue用超链接控制表单的提交,所以不用action手动提交表单。
<form method="post">
<input type="hidden" name="_method" value="delete">
</form>
为这个超链接绑定了一个点击事件,通过vue处理这个点击事件,form表单是最后提交请求的方式,vue里面设置的阻止超链接的默认提交,而改为了vue里面设置的表单提交的方式。
vue.js文件有两次添加不成功
此时就需要vue的js文件,刚在static配置完,打包的中会没有static文件(服务器中会没有),此时需要在LifeStyle中重新打包package,这时就会在服务器中部署。此时还是访问不了的,因为我们在实现SpringMVC的时候配置了一个前端控制器Dispatcher,请求路径的映射是一个斜线,表示所有请求,所以我们当前访问我们的静态资源是被我们的SpringMVC的前端控制器处理的,但是静态资源不能被SpringMVC处理,在web阶段讲过一个默认的servlet,叫defaultservlet,这个东西才是处理静态资源的servlet。
在springMVC.xml中配置开放静态资源的defaultservlet
<!--开放对静态资源的访问-->
<mvc:default-servlet-handler/>
静态资源在访问的时候先被SpringMVC(前端控制器)进行处理,如果在控制器中找不到相对应的请求映射,就会交给咱们默认的servlet进行处理。
<table id="dataTable" border="1" cellspacing="0" cellpadding="0" style="text-align: center;">
<tr>
<!--合并列为5-->
<th colspan="5">Employee Info</th>
</tr>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>options (<a th:href="@{/toAdd}">add</a> )</th>
</tr>
<!--each这里是代表我们要遍历的每一个数据,因为我们的数据是在请求域中去放的,所以我们要用${}去访问-->
<tr th:each="employee : ${employeeList}">
<!--不能直接在td里面${employee.id},因为我们当前在td标签里面去写的话,会被当成文本原样解析
所以要想操作文本内容,应该用th:text
-->
<td th:text="${employee.id}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<td th:text="${employee.gender}"></td>
<td>
<!--但是我们先不需要绑定数据,仅仅先要处理我们超链接的点击事件-->
<a @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
<a href="">update</a>
</td>
</tr>
</table>
<form id="deleteForm" method="post">
<input type="hidden" name="_method" value="delete">
</form>
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript">
<!--首先我们要先绑定vue当前的容器,容器需要包括我们要操作的元素,属性el,接下来我们要设置data来绑定数据-->
var vue = new Vue({
el:"#dataTable",
//methods这个属性是来处理当前的事件的,在里面写函数的名称,再对应我们当前的函数,在里面首先获取我们
//的form表单
methods:{
deleteEmployee:function (event){
//用原生js获取form表单
//根据id获取表单元素
var deleteForm = document.getElementById("deleteForm");
//form表单没有action,那么我们就要先给action赋值,
// 它才能提交,因为如果没有action或者action没有值就会提交到当前页面,要把它提交到
// 触发事件的超链接href那里,event表示当前触发的事件,下面的target指触发事件的元素,也就是
// 这个超链接,在.href就能获得当前触发事件的超链接的href属性,thymeleaf先解析
// 所以不用写th:href
//将触发点击事件的超链接的href属性赋值给表单的action
deleteForm.action = event.target.href;
//提交表单
deleteForm.submit();
//注意标签的默认行为,超链接点击之后就算你绑定了有点击事件,它也会跳转页面,
//像sumbit()按钮,就算你绑定了点击事件,它会先执行事件,再提交表单,所以要取消默认行为。
//取消超链表的默认行为
event.preventDefault();
}
}
});
</script>
@RequestMapping(value = "/employee/{id}",method = RequestMethod.DELETE)
//要想获得路径中占位符所表示的数据,应该再形参位置设置形参,通过@PathVariable("id"),将占位符表示的值
//与形参中进行绑定
public String deleteEmployee(@PathVariable("id") Integer id){
employeeDao.delete(id);
//我们应该跳转到列表页面,不能直接跳列表页面,因为列表页面是由上面的这个控制器来完成的
//所以应该用转发或者重定向来return上面控制器那个请求,
//但是要用重定向,让浏览器发送一个新的请求,来显示上面控制器方法的那个地址
return "redirect:/employee";
}
以上是删除功能的操作。
3、增加员工操作
1、在员工列表页面中添加超链接,跳转到一个添加员工的页面
<th>options (<a th:href="@{/toAdd}">add</a>)</th>
2、因为只需要页面视图的跳转,所以可以在SpringMVC中配置标签
<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
3、在创建增加员工的页面,在里面写一个表单就可以了,因为添加就是用post方式提交,必须是用
th:action,不然解析不了里面的地址
<form th:action="@{/employee}" method="post">
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/>
<input type="submit" value="add"><br>
</form>
4、在写控制器方法获取表单中的属性数据
@RequestMapping(value = "/employee",method = RequestMethod.POST)
public String addEmployee(Employee employee){
employeeDao.save(employee);
return "redirect:/employee";
}
4、根据员工id修改员工信息(修改功能)
修改功能与删除功能差不多,但是修改功能不能像删除功能一样点击直接实现删除功能,点击之后也要有相对应的页面,相对应的表单。
<a th:href="@{'/employee/' + ${employee.id}}">update</a>
在employee_list.html表单中添加上面超链接,根据传入的id值跳转到相对应的控制器方法,有控制器方法里面的@PathVariable("id") Integer id 参数获取id的值,利用Model model参数向我们的request域对象中进行共享,根据id通过employeeDao.get(id)方法获取用户对象,这个对象就是要我们要修改的用户信息,此时就用addAttribute方法放入employee的键值对,再跳转到employee_update对应的修改页面。
@RequestMapping(value = "/employee/{id}",method = RequestMethod.GET)
public String getEmployeeById(@PathVariable("id") Integer id,Model model){
Employee employee = employeeDao.get(id);
model.addAttribute("employee",employee);
return "employee_update";
}
此时就在employee_update进行回显(把th:value="${employee.id}"解析的数值写到表单里)
<form th:action="@{/employee}" method="post">
<input type="hidden" name="_method" value="put">
<input type="hidden" name="id" th:value="${employee.id}">
lastName: <input type="text" name="lastName" th:value="${employee.lastName}"><br>
email: <input type="text" name="email" th:value="${employee.email}"><br>
gender: <input type="radio" name="gender" value="1" th:field="${employee.gender}">male
<input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br/>
<input type="submit" value="update"><br>
</form>
单选框回显,需要th:field="${employee.id}",就会拿着field的值与value进行比较,如果一致就会自动添加checked = "checked",最后id也要回显,但是对用户没用,所以用隐藏域。
此时表单会提交到方法为put的/employee的请求
此时再写一个控制器方法保存修改完后的employee数据,这个方法是向Map<Integer, Employee>
的对象employees中put(id,employee);再重定向到到显示所有数据的/employee中,因为重定向默认是get,所以说可以重名
@RequestMapping(value="/employee",method = RequestMethod.PUT)
public String updateEmployee(Employee employee){
//这个方法会判断id是否会重复,无重复会加1,有重复那么添加的数据会覆盖原来的数据
employeeDao.save(employee);
return "redirect:/employee";
}