SpringBoot(4)—— Web开发的CRUD

Web开发(CRUD)


一、实验要求

1. 使用Rest风格:URI+请求方式
实验功能请求URI请求方式
查询所有员工empsGET
查询员工(来到修改页面)emp/{id}GET
来到添加页面empGET
添加员工empPOST
来到修改页面(查出员工信息进行回写)emp/{id}GET
修改员工empPUT
删除员工emp/{id}DELETE
2. 实体类和Dao:

/entities/Employee:员工类

	private Integer id;
    private String lastName;

    private String email;
    //1 male, 0 female
    private Integer gender;
    private Department department;
    private Date birth;

/entities/Department:部门类

	private Integer id;
	private String departmentName;

/dao/EmployeeDao

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

/dao/DepartmentDao

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

二、查询所有员工

1. 创建EmployeeController类,处理各种请求
2. 在EmployeeController中定义list方法,发送emps请求+GET请求方式(GetMapping),查询所有员工,返回/templates/emp/list.html列表页面

具体代码:
EmployeeController

@Controller
public class EmployeeController {

    /*
     * 将EmployeeDao自动注入,目前Dao没有涉及到数据库操作,直接在Dao中定义了一些Emp
     */
    @Autowired
    private EmployeeDao employeeDao;
    
    /*
     * 查询所有员工
     */
    @GetMapping("/emps")
    public String list(Model model){
        // 查询所有员工
        Collection<Employee> employees = employeeDao.getAll();

        model.addAttribute("emps", employees);

        return "emp/list";
    }
    
}

(1)使用@GetMapping("/emps")发送emp+GET请求,返回"emp/list"页面
(2)将查询到的员工employees存储到Model中,用于在页面调用

注意:thymeleaf默认会进行拼串:找到classpath:/templates/emp/list.html页面

public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
3. 抽取并引入页面的公共片段:顶部和侧边栏

(1)抽取公共片段(为公共片段命名):
- <div th:fragment="片段名">
- <nav id="片段名>
(2)从dashboard模板中引入公共片段:
- <div th:insert="~{模板名::片段名}">:将公共片段整个插入到需要引入的元素的div
- <div th:replace="模板名::片段名">:将需要引入的元素(包括div)替换为公共片段
- th:include:将被引入的片段的内容包含进这个标签中
- 使用以上三种方式引入,可以不写~{ }
(3)将dashboard模板中定义的公共片段也抽取出来,单独放在/templates/commons/bar.html
(4)对公共片段的侧边栏设置高亮显示
- 点击dashboard,url指向/main.html页面
- 点击员工管理,url发送/emps请求,指向list.html页面

具体代码:
/templates/commons/bar.html:抽取出来的公共片段

<!-- topbar -->
<!-- 将顶部公共页面抽取出来 th:fragment="topbar" -->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">

    <!--	显示登录的用户名		-->
    <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>
    <!-- ...省略... -->
</nav>

<!-- sidebar -->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" id="sidebar">
	...省略...
	<li class="nav-item">
		<a class="nav-link active" href="#" th:href="@{/main.html}"
	       th:class="${activeUri=='main.html'?'nav-link active': 'nav-link'}">
	                    <!-- ...省略... -->
	                    Dashboard <span class="sr-only">(current)</span>
	    </a>
    </li>

	<li class="nav-item">

                <!--	点击员工管理,查询所有员工,发送/emps请求	-->
                <!--    将sidebar的员工管理点击后指向emps
                          th:class:判断Uri,如果是emps,那么就高亮
                      -->
                <a class="nav-link active " href="#" th:href="@{/emps}"
                   th:class="${activeUri=='emps'?'nav-link active':'nav-link'}">
					<!-- ...省略... -->
                    员工管理
                </a>
   </li>

(1)使用th:fragment="topbar"定义抽取出来的头部片段,使用id="sidebar"定义抽取出来的侧边栏片段
(2)在侧边栏sidebar中,使用th:href="@{/main.html}"来替换掉原生属性,使得点击侧边栏上的dashboard可以指向main.html,使用th:class="${activeUri=='main.html'?'nav-link active': 'nav-link'}"来进行判断,如果当前uri是main.html,那么高亮。
(3)在侧边栏sidebar中,使用th:href="@{/emps}"来替换掉原生属性,使得点击侧边栏上的员工管理可以发送emps请求,使用th:class="${activeUri=='emps'?'nav-link active': 'nav-link'}"来进行判断,如果当前uri是emps,那么高亮。


/templates/dashboard.html:引入带参数的公共片段,使之高亮

<body>
	<div th:replace="commons/bar::topbar"></div>

	<div class="container-fluid">
		<div class="row">
			<div th:replace="commons/bar::#sidebar(activeUri='main.html')"></div>
			<!-- ...省略... -->
		</div>
	</div>

(1)使用<div th:replace="commons/bar::topbar"></div>来引入定义的头部公共片段
(2)使用<div th:replace="commons/bar::#sidebar(activeUri='main.html')"></div>来引入定义的侧边栏公共片段,并且带上了参数(activeUri='main.html'),这里的( )表示?,当前在dashboard页面下,uri=main.html,因此高亮。


/templates/emp/list.html:引入带参数的公共片段,使之高亮

<body>
	<div th:replace="commons/bar::topbar"></div>

	<div class="container-fluid">
		<div class="row">
			<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>
			<!-- ...省略... -->
		</div>
	</div>

(1)使用<div th:replace="commons/bar::topbar"></div>来引入定义的头部公共片段
(2)使用<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>来引入定义的侧边栏公共片段,并且带上了参数(activeUri='emps'),这里的( )表示?,当前发送emps请求,在list.html页面下,uri=emps,因此高亮。

4. 将Controller中查询到的emps在页面遍历显示:

EmployeeController中我们使用model.addAttribute("emps", employees);将查询到的员工数据都保存在了model里,那么在list页面可以使用${emps.属性名}来调用

list.html页面:
(1)列名:

	<thead>
		<tr>
			<th>#</th>
			<th>lastName</th>
			<th>email</th>
			<th>gender</th>
			<th>department</th>
			<th>birth</th>
			<th>操作</th>
		</tr>
	</thead>

(2)显示数据:

	<tbody>
		<tr th:each="emp:${emps}">
			<td th:text="${emp.id}"></td>
			<td>[[${emp.lastName}]]</td>
			<td th:text="${emp.email}"></td>
			<td th:text="${emp.gender}==0?'':''"></td>
			<td th:text="${emp.department.departmentName}"></td>
			<td th:text="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}"></td>
		</tr>
	</tbody>

tr标签里使用th:each="emp:${emps}"遍历存储在model里的emps数据,每次遍历到的emp,使用th:text="${emp.属性名}"来获得具体数据。


三、添加员工

1. 在list.html页面配置员工添加按钮,发送/emp+GET请求
2. 在EmployeeController中定义toAddPage方法,发送emp+GET请求来到添加员工的页面/templates/emp/add.html

具体代码:
list.html

<h2><a class="btn btn-sm btn-success" href="emp" th:href="@{/emp}">员工添加</a></h2>

(1)使用th:href="@{/emp}"指向emp的请求


EmployeeController

	@GetMapping("/emp")
    public String toAddPage(Model model){
        // TODO 6.6.4 查出所有部门放到model里,在页面显示
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("depts", departments);

        // 转到添加页面
        return "emp/add";
    }

(1)使用@GetMapping("/emp")发送emp+GET请求,返回"emp/add"页面
(2)为了方便在添加页面上部门信息选项的显示,在这里先将部门departments查询出来存储到Model


3. 在add.html页面配置每个添加的信息项
4. 配置添加按钮,将表单设置成emp+POST请求
5. 在EmployeeController中定义addEmp方法,发送emp+POST请求,调用EmployeeDao.save方法保存添加的员工,添加完成后重定向到list.html/页面

具体代码:
add.html

			<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">

					<!-- 设置成emp+POST方式 -->
					<form th:action="@{/emp}" method="post">
						<div class="form-group">
							<label>LastName</label>
							<input name="lastName" type="text" class="form-control" placeholder="zhangsan" >
						</div>

						<div class="form-group">
							<label>Email</label>
							<input name="email" type="email" class="form-control" placeholder="zhangsan@Lemon.com" >
						</div>

						<div class="form-group">
							<label>Gender</label>
							<div class="form-check form-check-inline">
								<input class="form-check-input" type="radio" name="gender" value="1" >
								<label class="form-check-label"></label>
							</div>
							<div class="form-check form-check-inline">
								<input class="form-check-input" type="radio" name="gender" value="0" >
								<label class="form-check-label"></label>
							</div>
						</div>

						<div class="form-group">
							<label>department</label>
							<select class="form-control" name="department.id">

								<!-- 显示每个部门,提交的是部门的id -->
								<option  th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
							</select>
						</div>

						<div class="form-group">
							<label>Birth</label>
							<input name="birth" type="text" class="form-control" placeholder="2020-6-14" >
						</div>

						<button type="submit" class="btn btn-primary">添加</button>
					</form>
				</main>

(1)将表单设置成emp+POST方式:<form th:action="@{/emp}" method="post">
(2)对于部门选项,在页面上显示部门的名称,提交时使用部门id进行提交:
<option th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
其中deptsEmployeeController中的方法保存在Model中的数据
(3)添加按钮:<button type="submit" class="btn btn-primary">添加</button>


EmployeeController

	@PostMapping("/emp")
    public String addEmp(Employee employee){
        System.out.println("保存的员工的信息:" + employee);

        // (3)调用dao方法保存添加的员工
        employeeDao.save(employee);

        return "redirect:/emps";
    }

(1)使用@PostMapping("/emp")发送emp+POST请求,使用employeeDao.save(employee)来保存添加的员工信息
(2)添加完成后要求仍然返回到list,html页面,但是不能直接return "emp/list",这样的话数据不会更新,可以使用重定向/转发
(3)这里使用重定向到/emps请求:"redirect:/emps",而/emps请求是list方法的请求,会返回list.html页面:return "emp/list";
(4)注意:SpringMVC自动将请求参数和入参对象的属性进行绑定,要求请求参数的名字和JavaBean入参对象的属性名相同
(5)对于自定义日期格式:可以在主配置文件application.properties中添加配置:spring.mvc.format.date=yyyy-MM-dd


四、修改员工

1. 在list.html页面配置编辑按钮,发送/emp/{id}+GET请求
2. 在EmployeeController中定义toEditPage方法,发送emp/{id}+GET请求来到修改页面/templates/emp/update.html

具体代码:
list.html

<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.id}">编辑</a>

(1)使用拼串的方式加上当前遍历到的emp的id值:th:href="@{/emp/}+${emp.id}"


EmployeeController

@GetMapping("/emp/{id}")
    public String toEditPage(@PathVariable("id") Integer id, Model model){
        // 查询出当前员工
        Employee employee = employeeDao.get(id);
        // 保存查询到的员工数据
        model.addAttribute("emp", employee);

        // 页面要显示所有的部门列表
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("depts", departments);

        // 回到change修改页面
        return "emp/change";
    }

(1)因为要从传入的参数获取id值,才能针对具体某个员工进行修改,所以使用@PathVariable("id")注解


3. 来到update.html页面(和add页面类似),需要回显信息
4. 配置修改按钮,将表单设置成emp+PUT请求
5. 在EmployeeController中定义updateEmployee方法,发送emp+PUT请求,调用EmployeeDao.save方法保存添加的员工,修改完成后重定向到list.html/页面

具体代码:
update.html

			<form th:action="@{/emp}" method="post">

						<!-- 要发送PUT请求,修改员工数据 -->
						<input type="hidden" name="_method" value="put">
						<input type="hidden" name="id" th:value="${emp.id}">

						<div class="form-group">
							<label>LastName</label>

							<!-- TODO 回写内容 -->
							<input name="lastName" type="text" class="form-control" placeholder="zhangsan" th:value="${emp.lastName}">
						</div>

						<div class="form-group">
							<label>Email</label>
							<input name="email" type="email" class="form-control" placeholder="zhangsan@Lemon.com" th:value="${emp.email}">
						</div>

						<div class="form-group">
							<label>Gender</label>
							<div class="form-check form-check-inline">
								<input class="form-check-input" type="radio" name="gender" value="1" th:checked="${emp.gender==1}">
								<label class="form-check-label"></label>
							</div>
							<div class="form-check form-check-inline">
								<input class="form-check-input" type="radio" name="gender" value="0" th:checked="${emp.gender==0}">
								<label class="form-check-label"></label>
							</div>
						</div>

						<div class="form-group">
							<label>department</label>
							<select class="form-control" name="department.id">

								<!-- TODO 显示每个部门,提交的是部门的id -->
								<option th:selected="${dept.id==emp.department.id}" th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
							</select>
						</div>

						<div class="form-group">
							<label>Birth</label>
							<input name="birth" type="text" class="form-control" placeholder="zhangsan" th:value="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}">
						</div>

						<button type="submit" class="btn btn-primary">修改</button>
					</form>

(1)因为在toEditPage方法中根据发送的id信息获取到了该员工,并保存在了Model中:model.addAttribute("emp", employee);,所以只需要使用th:value="${emp.属性名}"即可回显查询到的员工信息

(2)对于gender属性,使用

th:checked="${emp.gender==1}"

来进行判断:如果查询到的员工性别为男,则选中。

(3)对于department属性,使用

th:selected="${dept.id==emp.department.id}" th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}"
  • th:each="dept:${depts}"遍历保存在Model中的depts所有部门信息,得到每一个部门dept
  • th:value="${dept.id}"获得遍历到的当前部门id
  • th:selected="${dept.id==emp.department.id}"判断当前遍历到的部门是否和要编辑查询到的emp的部门id相同
  • th:text="${dept.departmentName}":如果判断成立,则回显部门名称

(4)对于birth属性,使用

th:value="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}"

将编辑查询到的emp.birth属性使用dates.format来进行日期格式化

(5)对于id属性,并不需要显示在页面上,所以使用

<input type="hidden" name="id" th:value="${emp.id}">

来进行隐式输出

(6)创建一个input项,来发送PUT请求,name="_method"这个名称不能变!<input type="hidden" name="_method" value="put">

(7)<button type="submit" class="btn btn-primary">修改</button>:修改按钮

(8)注意:一定要在主配置文件中配置spring.mvc.hiddenmethod.filter.enabled=true,否则修改后还是发送POST请求,而不是(6)中指定的PUT请求


EmployeeController

	@PutMapping("/emp")
    public String updateEmployee(Employee employee){
        System.out.println("修改的员工数据:" + employee);
        // 修改后要保存,如果有id,map重新put进去
        employeeDao.save(employee);
    
        return "redirect:/emps";
    }

(1)使用@PutMapping("/emp")发送emp+PUT请求,使用employeeDao.save(employee)来保存信息
(2)使用"redirect:/emps"来重定向到list.html页面
(3)注意:如果要把add.htmlupdate.html合并在一起,那么可以加上一个判断th:if="${emp!=null}"来判断当前是修改还是添加,因为在修改时需要先查询id的员工信息,存储在Model中,所以emp不为空;而添加时不需要查询,emp为空。


五、删除员工

1. 在list.html页面配置删除按钮,发送/emp/{id}+DELETE请求
2. 在EmployeeController中添加deleteEmployee方法,发送emp/{id}+DELETE请求,调用EmployeeDao.delete方法删除指定id的员工,删除后重定向到list.html/页面
3. 美化删除按钮

具体代码:
list.html

<div>
	<div>
	<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">

		<!--	将list.html中的员工添加按钮设置可以跳转到添加页面				-->
		<h2><a class="btn btn-sm btn-success" href="emp" th:href="@{/emp}">员工添加</a></h2>

		<button th:attr="del_uri=@{/emp/}+${emp.id}"  class="btn btn-sm btn-danger deleteBtn">删除</button>
		
		<!-- 省略  -->
		
	</main>

	<form id="deleteEmpForm" method="post">
		<input type="hidden" name="_method" value="delete"/>
	</form>
	</div>
</div>

		<script type="text/javascript" src="asserts/js/jquery-3.2.1.slim.min.js" th:src="@{/webjars/jquery/3.3.1/jquery.js}"></script>
		<script type="text/javascript" src="asserts/js/popper.min.js" th:src="@{/webjars/popper.js/1.16.1/dist/popper.js}"></script>
		<script type="text/javascript" src="asserts/js/bootstrap.min.js" th:src="@{/webjars/bootstrap/4.5.0/js/bootstrap.js}"></script>

		<!-- Icons -->
		<script type="text/javascript" src="asserts/js/feather.min.js" th:src="@{/asserts/js/feather.min.js}"></script>
		<script>
			feather.replace()
		</script>

		<script>
			$(".deleteBtn").click(function () {
				$("#deleteEmpForm").attr("action", $(this).attr("del_uri")).submit();
				return false;
			})
		</script>

(1)如果使用下面的配置,删除样式会挤到下一行去

	<form th:action="@{/emp/}+${emp.id}" method="post">
		<input type="hidden" name="_method" value="delete"/>
		<button type="submit" class="btn btn-sm btn-danger">删除</button>
	</form>

(2)如果样式丢失,要将三个script标签使用th:src="@{...}"替换掉原生属性

	th:src="@{/webjars/jquery/3.3.1/jquery.js}"
	th:src="@{/webjars/popper.js/1.16.1/dist/popper.js}"
	th:src="@{/webjars/bootstrap/4.5.0/js/bootstrap.js}"

EmployeeController

	@DeleteMapping("/emp/{id}")
    public String deleteEmployee(@PathVariable("id") Integer id){
        employeeDao.delete(id);

        return "redirect:/emps";
    }

(1)使用@DeleteMapping("/emp/{id}")发送emp/{id{+DELETE请求,使用employeeDao.delete(id)来保存信息
(2)使用"redirect:/emps"来重定向到list.html页面

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值