SpringBoot集成SpringMVC的CRUD项目实例
(1)默认访问首页
1)创建首页login.html
<!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" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="asserts/css/signin.css" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="dashboard.html">
<img class="mb-4" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label class="sr-only">Username</label>
<input type="text" class="form-control" placeholder="Username" required="" autofocus="">
<label class="sr-only">Password</label>
<input type="password" class="form-control" placeholder="Password" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">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>
2)创建自定义配置类MyMvcConfig
/**
* 使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
* @EnableWebMvc:这里不使用该注解,因为它会使SpringMVC自动配置失效
*/
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
/**
* 所有的WebMvcConfigurerAdapter组件都会一起起作用
*/
@Bean //将组件注册到容器中
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("login.html").setViewName("login");
}
};
return adapter;
}
}
(2)设置国际化功能
1)编写国际化配置文件,抽取页面需要显示的国际化资源文件
2)SpringBoot自动帮我们配置好了管理国际化资源文件的组件
3)通过页面获取配置文件中的国际化值
<body class="text-center">
<form class="form-signin" action="dashboard.html">
<img class="mb-4" src="asserts/img/bootstrap-solid.svg" th: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>
原理:
国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象);默认的就是根据请求头带来的区域信息获取Locale进行国际化 。
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
4)点击链接切换国际化
/**
* 获取区域信息对象
* 可以在链接上携带区域信息
*/
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 httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
5)点击切换中英文
(3)拦截器登录功能
1)创建登录控制器类LoginController
这里只是设置了登录名不为空并且密码为“123456”即可登录,并没有做过多的验证
/**
* 登录控制器类
*/
@Controller
public class LoginController {
@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 {
//登录失败
return "login";
}
}
}
2)在登录页面设置错误提示
3)创建登录拦截器类LoginHandlerInterceptor
/**
* 登录拦截器
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
//在目标方法之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if (user == null){
//没有登录
request.setAttribute("msg","还没有登录,请重新登录");
request.getRequestDispatcher("/login.html").forward(request,response);
return false;
}else{
//已登陆,放行请求
return true;
}
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
4)注册登录拦截器到SpringMVC容器中
5)运行结果
(4)员工信息查询
注意:
这里并没有使用连接数据库的操作,只是通过集合来进行数据的增删改
1)创建员工操作控制类EmployeeController,并添加查询方法
/**
* 员工管理控制器类
*/
@Controller
public class EmployeeController {
@Autowired
EmployeeDao employeeDao;
@Autowired
DepartmentDao departmentDao;
//查询所有员工返回列表页面
@GetMapping("/emps")
public String selectAllEmp(Model model){
//查询所有员工信息
Collection<Employee> employees = employeeDao.getAll();
//将查询到的集合放入请求域中
model.addAttribute("emps",employees);
//转发到emp目录下的list.html页面
return "emp/list";
}
}
2)创建展示所有员工信息页面list.html(这里页面将公共部分抽取出去另外一个页面,当需要的时候将其引入进来即可,比如页面的上边栏和侧边栏)
<body>
<!--引入抽取的topbar-->
<!--模板名:会使用thymeleaf的前后缀配置规则进行解析-->
<div th:replace="commons/bar::topbar"></div>
<div class="container-fluid">
<div class="row">
<!--引入侧边栏-->
<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2><a class="btn btn-sm btn-success" href="emp" th:href="@{/emp}">员工添加</a></h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<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="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}"></td>
<td>
<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.id}">编辑</a>
<button class="btn btn-sm btn-danger deleteBtn">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</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>
</body>
3)运行结果
(5)员工信息添加
1)在控制类中添加跳转到添加页面的方法
//通过点击员工管理链接传入“/emp”来到员工添加页面
@GetMapping("/emp")
public String toAddPage(Model model){
//查询所有部门名称信息,在部门选择下拉框中显示
Collection<Department> departments = departmentDao.getDepartments();
//将查询到的集合放入请求域中
model.addAttribute("depts",departments);
//转发到emp目录下的add.html页面
return "emp/add";
}
2)创建添加页面add.html
<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-->
<!--模板名:会使用thymeleaf的前后缀配置规则进行解析-->
<div th:replace="commons/bar::topbar"></div>
<div class="container-fluid">
<div class="row">
<!--引入侧边栏-->
<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<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@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>
<!--提交的是部门的id-->
<select class="form-control" name="department.id">
<option 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">
</div>
<button type="submit" class="btn btn-primary">添加</button>
</form>
</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>
</body>
3)添加提交响应方法,然后再重定向/emps链接到员工列表页面展示
//员工添加
@PostMapping("/emp")
public String addEmp(Employee employee){
//调用保存员工的方法
employeeDao.save(employee);
//重定向到员工列表页面
//这里为啥不能直接使用“/emps”呢?因为这样会返回到templates目录下的emps目录了
return "redirect:/emps";
}
4)运行结果
(6)员工信息修改
1)点击编辑链接传进路径,添加对应的查询指定员工信息方法,然后再来到员工修改页面(这里修改页面也为添加页面)
//先查询指定员工信息,再来到员工修改页面
@GetMapping("/emp/{id}")
public String toEditPage(@PathVariable("id") Integer id,Model model){
//获取传进来的员工id值查询该员工信息
Employee employee = employeeDao.get(id);
//将查询到的该员工信息放入请求域中
model.addAttribute("emp",employee);
//查询所有部门名称信息,在部门选择下拉框中显示
Collection<Department> departments = departmentDao.getDepartments();
//将查询到的集合放入请求域中
model.addAttribute("depts",departments);
//返回修改页面(这里add.html页面是一个添加和修改二合一的页面)
return "emp/add";
}
2)在添加页面add.html做如下修改
3)添加修改提交响应方法,然后再重定向/emps链接到员工列表页面展示
//员工信息修改:注意需要从页面中提交员工id
@PutMapping("/emp")
public String updateEmp(Employee employee){
employeeDao.save(employee);
return "redirect:/emps";
}
4)运行结果
(7)员工信息删除
1)在list.html页面中添加删除链接,这里结合script来使用(这里实现有点难理解)
2)添加对应的删除方法
//员工删除
@DeleteMapping("/emp/{id}")
public String deleteEmp(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
3)运行结果
最后:为了方便大家学习,附上完整代码地址