SpringBoot(四)——RestfulCRUD练习

七、练习

1、准备工作

将写好的登录页面login.html放入静态资源文件夹内,准备作为首页,并且设置一个原首页。

2、设置访问首页

首先设置一个空页面index.html作为首页,通过它去转到登录界面
在这里插入图片描述
设置页面转换:

    @RequestMapping({"/","/index.html"})
    public String index(){
        return "index";
    }

注意
在这里不加 @ResponseBody的原因是,这个注解的作用是把return的数据以json数据类型返回到HTTP response body中(一般用于异步交互),而不会被解析为页面跳转行为,如果加上了此注解,则会直接显示login这五个char,因此在这里不能添加。
但是如果我们进行login页面访问的时候都需要刷新一遍数据,未免有点太麻烦了,所以可以addViewController添加视图映射,启动的时候自动就映射到login页面。
因此不要忘记将刚才写的代码注释掉

@Bean //将组件注册在容器
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
                registry.addViewController("/main.html").setViewName("dashboard");
            }
         };
         return adapter;
}

在这里需要修改一下资源引用,一般SpringBoot都是默认从静态资源文件夹获取到的,在这里我们在引用一下webjars,用th:href的好处就是:如果有一天项目的访问名改变,比如我们是在application.properties中加了个server.context-path=/xxx,就是说,给这个域名加了个前缀,如果我们不用th:href,不会帮我们加上的,但是使用之后,就会默认把/xxx加上,防止我们出现404的问题

			<!--Bootstrap core CSS-->
            <li href="asserts/css/bootstrap.min.css" th:href="@{/}" rel="stylesheet"></li>

填入th:href的具体方法是:找到前面link href的路径在webjars的目录下,添加进来

		<!-- Bootstrap core CSS -->
		<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">

		<!-- Custom styles for this template -->
		<link href="asserts/css/dashboard.css" th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
3、国际化

在resources目录下创建国际化配置文件
在这里插入图片描述
切换到Resource Bundle
在这里插入图片描述
在properties配置文件中配置上

# 国际化配置文件(包名.基础名)
spring.messages.basename=i18n.login

编译之后SpringBoot会自动配置好管理国际化资源文件的组件
让页面获取到国际化的值

<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
			<label class="sr-only" th:text="#{login.username}">Username</label>
			<input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
			<label class="sr-only" th:text="#{login.password}">Password</label>
			<input type="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="">
			<div class="checkbox mb-3">
			<label>
          		<input type="checkbox" value="remember-me"/> [[#{login.remember}]]
        	</label>
			</div>
			<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>

运行之后会出现乱码,我们需要做如下配置修改
在这里插入图片描述
运行的效果如下:
在这里插入图片描述
通过一个超链接去转换国际化的选项,放在任意的位置即可

	<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>

运行首页,点击超链接,地址名会改变成对应区域的链接,因为还使用了thymeleaf,所以不需要用问号代替参数,直接用小括号,小括号内的值就是value,但是这时我们还无法做到通过链接来达到国际化,所以需要写一个区域信息解析器

/**
 * 可以在连接上携带区域信息
 */
public class MyLocaleResolver implements LocaleResolver {
    
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if(!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

写完区域信息解析器之后发现,并没有生效,因为在LocaleResover底层源代码中,发现有一个@ConditionalOnMissingBean,意思是在我们没有区域信息解析器的时候才会去添加,而底层代码中,有一个AcceptHeaderLocaleResolver会被默认使用到,而且也在自动配置中,所以会默认直接使用这个区域信息解析器,而无法使用到我们手写的。
所以需要在配置类中将组件手动添加进去

@Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }

运行,国际化界面就可以完成了。
登录界面代码:

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<title>Signin Template for Bootstrap</title>
		<!-- Bootstrap core CSS -->
		<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
		<!-- Custom styles for this template -->
		<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
	</head>

	<body class="text-center">
		<form class="form-signin" action="dashboard.html">
			<img class="mb-4" th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
			<label class="sr-only" th:text="#{login.username}">Username</label>
			<input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
			<label class="sr-only" th:text="#{login.password}">Password</label>
			<input type="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="">
			<div class="checkbox mb-3">
				<label>
          		<input type="checkbox" value="remember-me"/> [[#{login.remember}]]
        </label>
			</div>
			<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
			<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
			<a class="btn btn-sm">中文</a>
			<a class="btn btn-sm">English</a>
		</form>
	</body>
</html>
4、登录

开发期间模板引擎页面修改以后,要实时生效,所以需要修改如下配置:
1、禁用模板引擎的缓存

# 禁用缓存
spring.thymeleaf.cache=false 

2、页面修改完成之后ctrl+F9:重新编译
在login.html中使用thymeleaf模拟一个post的登录请求
在这里插入图片描述
对login请求写一个登录验证方法

@Controller
public class LoginController {

//    @DeleteMapping
//    @PutMapping
//    @GetMapping

    //@RequestMapping(value = "/user/login",method = RequestMethod.POST)
    @PostMapping(value = "/user/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("password") String password,
                        Map<String,Object> map, HttpSession session){
        if(!StringUtils.isEmpty(username) && "123456".equals(password)){
            //登陆成功,防止表单重复提交,可以重定向到主页
            session.setAttribute("loginUser",username);
            return "redirect:/main.html";
        }else{
            //登陆失败
            map.put("msg","用户名密码错误");
            return  "login";
        }
    }
}

不能让表单重复提交,可以重定向到一个main页面,使用redirect:/main.html然后把页面通过视图映射,映射到我们刚刚的dashboard即可。

 @Bean //将组件注册在容器
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
                registry.addViewController("/main.html").setViewName("dashboard");
            }
        };
        return adapter;
    }
@Controller
public class LoginController {

//    @DeleteMapping
//    @PutMapping
//    @GetMapping

    //@RequestMapping(value = "/user/login",method = RequestMethod.POST)
    @PostMapping(value = "/user/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("password") String password,
                        Map<String,Object> map, HttpSession session){
        if(!StringUtils.isEmpty(username) && "123456".equals(password)){
            //登陆成功,防止表单重复提交,可以重定向到主页
            session.setAttribute("loginUser",username);
            return "redirect:/main.html";
        }else{
            //登陆失败
            map.put("msg","用户名密码错误");
            return  "login";
       }
    }
}

登录,发现无法识别username,这是因为没有在login内指明我们传给map的key值,也就是username,所以要在下面声明一下username和password
在这里插入图片描述
如果我们password输入错误了,也需要给予server端一个提示说输入错误了,所以要在login中,在Please Sign in这一行加上

<!--判断计算,当if成立,其他标签才能生效,原理是标签的优先级-->
<p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

可以登录到dashboard页面,但是有一个问题,我们可以通过地址跨过验证界面,跳到登录后的界面,这时我们需要设置一个拦截器,把登录过的username放进一个HTTPSession的对象中存起来,从而其他的用户会被拦截。
书写拦截器

/**
 * 登陆检查,没有登录的用户无法进入登录后的页面
 */
public class LoginHandlerInterceptor implements HandlerInterceptor {
    //目标方法执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object user = request.getSession().getAttribute("loginUser");
        if(user == null){
            //未登陆,返回登陆页面
            request.setAttribute("msg","没有权限请先登陆");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else{
            //已登陆,放行请求
            return true;
        }

    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

在WebMvcConfigurerAdapter注册拦截器

 //注册拦截器
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                //super.addInterceptors(registry);
                //静态资源;  *.css , *.js
                //SpringBoot已经做好了静态资源映射
                registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
                        .excludePathPatterns("/index.html","/","/user/login");
            }

注意:一定要写上/,不然会报405
dashboard.html代码

<!DOCTYPE html>
<!-- saved from url=(0052)http://getbootstrap.com/docs/4.0/examples/dashboard/ -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">

		<title>Dashboard Template for Bootstrap</title>
		<!-- Bootstrap core CSS -->
		<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">

		<!-- Custom styles for this template -->
		<link href="asserts/css/dashboard.css" th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
		<style type="text/css">
			/* Chart.js */
			
			@-webkit-keyframes chartjs-render-animation {
				from {
					opacity: 0.99
				}
				to {
					opacity: 1
				}
			}
			
			@keyframes chartjs-render-animation {
				from {
					opacity: 0.99
				}
				to {
					opacity: 1
				}
			}
			
			.chartjs-render-monitor {
				-webkit-animation: chartjs-render-animation 0.001s;
				animation: chartjs-render-animation 0.001s;
			}
		</style>
	</head>

	<body>
		<!--引入topbar-->
		<div th:replace="commons/bar::topbar"></div>
		<div class="container-fluid">
			<div class="row">
				<!--引入sidebar-->
				<div th:replace="commons/bar::#sidebar(activeUri='main.html')"></div>
				<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
					<div class="chartjs-size-monitor" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: hidden; pointer-events: none; visibility: hidden; z-index: -1;">
						<div class="chartjs-size-monitor-expand" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;">
							<div style="position:absolute;width:1000000px;height:1000000px;left:0;top:0"></div>
						</div>
						<div class="chartjs-size-monitor-shrink" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;">
							<div style="position:absolute;width:200%;height:200%;left:0; top:0"></div>
						</div>
					</div>
					<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
						<h1 class="h2">Dashboard</h1>
						<div class="btn-toolbar mb-2 mb-md-0">
							<div class="btn-group mr-2">
								<button class="btn btn-sm btn-outline-secondary">Share</button>
								<button class="btn btn-sm btn-outline-secondary">Export</button>
							</div>
							<button class="btn btn-sm btn-outline-secondary dropdown-toggle">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-calendar"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
                This week
              </button>
						</div>
					</div>

					<canvas class="my-4 chartjs-render-monitor" id="myChart" width="1076" height="454" style="display: block; width: 1076px; height: 454px;"></canvas>

					
				</main>
			</div>
		</div>

		<!-- Bootstrap core JavaScript
    ================================================== -->
		<!-- Placed at the end of the document so the pages load faster -->
		<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.11.1/dist/popper.js}"></script>
		<script type="text/javascript" src="asserts/js/bootstrap.min.js" th:src="@{/webjars/bootstrap/4.0.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>

		<!-- Graphs -->
		<script type="text/javascript" src="asserts/js/Chart.min.js" th:src="@{/asserts/js/Chart.min.js}"></script>
		<script>
			var ctx = document.getElementById("myChart");
			var myChart = new Chart(ctx, {
				type: 'line',
				data: {
					labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
					datasets: [{
						data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
						lineTension: 0,
						backgroundColor: 'transparent',
						borderColor: '#007bff',
						borderWidth: 4,
						pointBackgroundColor: '#007bff'
					}]
				},
				options: {
					scales: {
						yAxes: [{
							ticks: {
								beginAtZero: false
							}
						}]
					},
					legend: {
						display: false,
					}
				}
			});
		</script>
	</body>
</html>
5、CRUD-员工列表
实验需求:
<1>、RestfulCRUD

URI: /资源名称/资源标识 HTTP请求方式区分对资源CRUD操作

普通CRUD(uri来区分操作)RestfulCRUD
查询getEmpemp—GET
添加addEmp?xxxemp—POST
修改updateEmp?id=xxx&xxx=xxemp/{id}—PUT
删除deleteEmp?id=1emp/{id}—DELETE
<2>、实验请求架构
实验功能请求URI请求方式
查询所有员工empsGET
查询某个员工(来到修改页面)emp/1GET
来到添加页面empGET
添加员工empPOST
来到修改页面(查出员工进行信息回显)emp/1GET
修改员工empPUT
删除员工emp/1DELETE
实现方法
<1>、员工列表

把要跳转的list页面在dashboard.html中找到位置,然后用thymeleaf模板引擎定义RequestMapping属性,方便后面设置请求能够顺利到达页面
在这里插入图片描述
编写一个映射方法通过点击Customer到达list.html的方法
return的时候不需要写上templates就是因为在ThymeleafProperties配置中已经为我们默认配置了这个路径头。

@Controller
public class EmployeeController {
    @Autowired
    EmployeeDao employeeDao;

    //查询所有员工返回列表页面
    @GetMapping("/emps")
    public String  list(Model model){
        Collection<Employee> employees = employeeDao.getAll();

        //放在请求域中
        model.addAttribute("emps",employees);
        // thymeleaf默认就会拼串
        // classpath:/templates/xxxx.html
        return "emp/list";
    }
}
<2>、thymeleaf公共页面元素抽取
(1)、抽取片段
抽取公共片段
<div th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</div>
(2)、引入片段
引入公共片段
<div th:insert="~{footer :: copy}"></div>
~{templatename::selector}:模板名::选择器
~{templatename::fragmentname}:模板名::片段名
(3)、实验(1、2)

把dashboard的顶部栏,给list页面使用
在这里插入图片描述
dashboard的顶部栏
在这里插入图片描述
list的顶部栏
现在要实现,使用上面介绍的公共元素抽取和引用的方法来实现统一,同时节省写代码的时间,首先需要抽取元素:

<!--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>
    <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
    <ul class="navbar-nav px-3">
        <li class="nav-item text-nowrap">
            <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
        </li>
    </ul>
</nav>

在dashboard找到顶部栏的源代码,加上了fragment属性和topbar属性值
再去到list找到顶部栏进行替换

		<!--引入抽取的topbar-->
		<!--模板名:会使用thymeleaf的前后缀配置规则进行解析-->
		<div th:replace="commons/bar::topbar"></div>

注:
1.replace的功能片段在div标签中
2.引入功能的标签除了replace还有两种
th:insert:将公共片段整个插入到声明引入的元素中
th:replace:将声明引入的元素替换为公共片段
th:include:将被引入的片段的内容包含进这个标签中

(4)、参数化的片段签名

现在发现,虽然已经成功引入公共模板,但是并没有高亮的效果,然后我们来设置页面高亮,可以发现,只需要在对应的属性标签上使用active属性,就可以实现选项高亮,但是我们只有在真正点入页面的时候,大部分的选项卡应该是只有鼠标点上去才会变成高亮,所以我们现在将要实现这个功能
我们在1、2中声明th:fragment中都是只标记模板名,现在可以填入两个参数,那么在这个片段中就可以使用 这两个参数,然后在模板引用的时候也可以通过设置的两个参数进行导入。但是在声明fragment的时候也可以不生命具体的参数,而引入的时候也可以直接声明+引用
接下来我们在templates文件夹下创建一个commons目录,用来存放公共模板,并且新建一个html,在里面注入公共模板的代码

		<div th:replace="~{commons/bar :: topbar}"></div>
		<div th:replace="~{commons/bar :: #sidebar}"></div>

然后将模板引入代码对应的填到dashboard和list对应位置中
重新进行测试,发现没有问题
现在要实现进入到Employee Manage界面之后可以通过点击dashboard能够返回到原来的emps界面,我们来到bar进行thymeleaf模板引擎的引入

<a class="nav-link active"  href="#" th:href="@{/main.html}">

实现选项卡高亮功能,只有鼠标在选中的时候才会高亮,原理就是,因为高亮是设置到a标签的class属性上,所以只需要用th:class引入判断即可
首先设置list

<!--引入侧边栏-->
<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>

再设置dashboard

<!--引入sidebar-->
<div th:replace="commons/bar::#sidebar(activeUri='main.html')"></div>

重新进行a标签的书写,还没有指明activeUrl是干什么的
来到bar页面

<a class="nav-link active"
                   th:class="${activeUri=='main.html'?'nav-link active':'nav-link'}"
                   href="#" th:href="@{/main.html}">
 <a class="nav-link active" href="#" th:href="@{/emps}"
                th:class="${activeUri=='emps'?'nav-link active':'nav-link'}">
<3>、遍历取出员工数据

来到list页面
删除原来的tbody标签,自己手写一个tbody标签
目的是通过tbody里面放的一个遍历,达到输出所有员工数据功能。

    <thead>
			<tr>
				<th>#</th>
				<th>lastName</th>
				<th>email</th>
				<th>gender</th>
				<th>department</th>
				<th>birth</th>
				<th>操作</th>
			</tr>
	</thead>
	<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="${emp.birth}"></td>
			</tr>
	</tbody>

这时我们发现生日日期的格式和我们平时的格式不太一样,因此需要进行日期格式化

<td th:text="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}"></td>
<4>、CRUD操作
(1)、添加

在td标签内添加按钮来实现对员工列表的crud操作。首先添加按钮对应刚才添加的每一行的员工信息,添加到循环体中

<td>
	<button class="btn btn-sm btn-primary">edit</button>
	<button class="btn btn-sm btn-danger">delete</button>
</td>

需要通过点击员工添加按钮来到一个新的页面完成业务的实现,所以要把员工添加变成一个button,因为是a标签,所以发送get请求,来到emp界面

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

添加的表格模板来自于

<form>
	<div class="form-group">
		<label>LastName</label>
		<input type="text" class="form-control" placeholder="zhangsan">
	</div>
	<div class="form-group">
		<label>Email</label>
		<input type="email" class="form-control" placeholder="zhangsan@atguigu.com">
	</div>
	<div class="form-group">
		<label>Gender</label><br/>
		<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">
			<option>1</option>
			<option>2</option>
			<option>3</option>
			<option>4</option>
			<option>5</option>
		</select>
	</div>
	<div class="form-group">
		<label>Birth</label>
		<input type="text" class="form-control" placeholder="zhangsan">
	</div>
	<button type="submit" class="btn btn-primary">添加</button>
</form>

增加一个新的功能:点完员工添加之后能够通过显示部门然后再添加员工
首先要把department的信息以集合的方式用get请求传到add界面内,让add界面能够顺利使用

//来到员工添加页面
    @GetMapping("/emp")
    public String toAddPage(Model model){
        //来到添加页面,查出所有的部门,在页面显示
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("depts",departments);
        return "emp/add";
    }

显示出部门的信息,要使用到option属性,并且直接遍历每一个部门的Name

<!--提交的是部门的id-->
<select class="form-control" name="department.id">
	<option th:selected="${emp!=null}?${dept.id == emp.department.id}" th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
</select>

用thymeleaf模板去遍历department信息,然后用th:text显示departmentName信息,供添加的时候去选择。
然后点击页面下面的添加,进行添加请求,要用到action属性,以post请求去请求到。

    //员工添加
    //SpringMVC自动将请求参数和入参对象的属性进行一一绑定;要求请求参数的名字和javaBean入参的对象里面的属性名是一样的
    @PostMapping("/emp")
    public String addEmp(Employee employee){
        //来到员工列表页面
        System.out.println("保存的员工信息:"+employee);
        // redirect: 表示重定向到一个地址  /代表当前项目路径
        // forward: 表示转发到一个地址
        return "redirect:/emps";
    }

然后回到add页面找到表单去进行提交属性的定义
在这里插入图片描述
然后回到EmployeeController.java进行保存

	//员工添加
    //SpringMVC自动将请求参数和入参对象的属性进行一一绑定;要求请求参数的名字和javaBean入参的对象里面的属性名是一样的
    @PostMapping("/emp")
    public String addEmp(Employee employee){
        //来到员工列表页面

        System.out.println("保存的员工信息:"+employee);
        //保存员工
        employeeDao.save(employee);
        // redirect: 表示重定向到一个地址  /代表当前项目路径
        // forward: 表示转发到一个地址
        return "redirect:/emps";
    }

注意:日期格式一定要对,不然会出现405的错误

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

id在遍历的过程中是不断变化的,所以无法直接在进行请求的时候直接标注,只能用拼接的方法进行请求。请求路径必然是/emp,后面带的变量id就要使用{id}进行请求了,然后我们来写页面跳转的代码:

	//来到修改页面,查出当前员工,在页面回显
    @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);
        //回到修改页面(add是一个修改添加二合一的页面);
        return "emp/add";
    }

为了能够方便修改,所以在add界面要修改的对应地方加上th:value表示选中内容即可,比如:th:value="${emp.id}"
在遍历阶段,要写成

<option th:selected="${dept.id == emp.department.id}" th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>

在实现添加和修改页面二合一的时候需要使用:

<input class="form-check-input" type="radio" name="gender" value="1" th:checked="${emp!=null}?${emp.gender==1}">

修改之后重新测试Edit按钮发现成功,但是发现添加又出了问题,因为这是二合一页面,所以接下来要这样:在刚才所有添加的标签上添加

${emp!=null}

接下来要修改发送请求,因为只有在edit的时候才会修改,因此要加上一个判断

<input type="hidden" name="_method" value="put" th:if="${emp!=null}"/>

编写put请求修改后的跳转页面,因为默认不支持put请求,只支持get和post

//员工修改;需要提交员工id;
    @PutMapping("/emp")
    public String updateEmployee(Employee employee){
        System.out.println("修改的员工数据:"+employee);
        employeeDao.save(employee);
        return "redirect:/emps";
    }

观察到控制台的id=null,因为没有把无法修改的id值进行返回,所以要默认进行返回

<input type="hidden" name="id" th:if="${emp!=null}" th:value="${emp.id}">
(3)、删除

以字符串拼接和delete请求去发送

<tbody>
	<tr th:each="emp:${emps}">
		<td>
			<button th:attr="del_uri=@{/emp/}+${emp.id}" class="btn btn-sm btn-danger deleteBtn">删除</button>
		</td>
	</tr>
</tbody>

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

还需要在list.html中编写删除的script

		<script>
			$(".deleteBtn").click(function(){
			    //删除当前员工的
			    $("#deleteEmpForm").attr("action",$(this).attr("del_uri")).submit();
			    return false;
            });
		</script>

编写员工删除的java代码

 	//员工删除
    @DeleteMapping("/emp/{id}")
    public String deleteEmployee(@PathVariable("id") Integer id){
        employeeDao.delete(id);
        return "redirect:/emps";
    }

运行效果图:
在这里插入图片描述
观察到按钮变成form表单,并且测试成功。
到此RestfulCRUD练习就完成了!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值