流程:

创建项目,勾选基本的几个开发工具还有webstarter

再创建包(service,control,config,dao,pojo)

再前往https://www.webjars.org/,选择bootstrap和jquery的依赖导入

注意:在导入jquery和bootstrap中如何导入我们的对应文件

<script type="text/javascript" src="webjars/jquery/3.6.0/jquery.js"></script>
<script type="text/javascript" src="webjars/bootstrap/5.0.1/js/bootstrap.js"></script>
<link rel="stylesheet" type="text/css" href="webjars/bootstrap/5.0.1/css/bootstrap.min.css">

导入thmeleaf依赖,并配置(不导入这个依赖,在templates文件中加载的html模板是找不到的)

尝试写一个index.html

<body class="text-center">
<form class="form-sigin">
<img class="mb-4 img-thumbnail" src="https://exploit-typora.oss-cn-shenzhen.aliyuncs.com/img/IMG_20210410_100617.png" alt="" width="200" height="200">
<h1 class="h3 mb-3 font-weight-normal">please login in</h1>
<label for="user-name" class="sr-only">username</label>
<!--注意:一定要用label标签把input标签包含起来,不然就导致input标签不居中-->
<label>
<input id="user-name" type="text" name="username" class="form-control" required="" autofocus="">
</label>
<label for="password" class="sr-only">password</label>
<label>
<input id="password" type="password" name="password" class="form-control" required="" autofocus="">
</label>
<br>
<div class="check-box mb-3">
<label>
<input type="checkbox" value="remember-me">remember
</label>
</div>
<button type="submit" class="btn btn-lg btn-primary btn-block">login</button>
<p class="mt-5 mb-3 text-muted"> 2020-2034</p>
<p class="btn btn-sm">中文</p>
<a class="btn btn-sm">English</a>
</form>
</body>

写一个配置类,把“/”和"/index"和"/index.html"都对应到index主页

@Configuration
public class ViewResolver implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
}

添加thmeleaf命名空间,和form的提交url

<html lang="en" xmlns:th=http://www.thymeleaf.org
xmlns:sec=http://www.thymeleaf.org/extras/spring-security
xmlns:shiro=http://www.pollix.at/thymeleaf/shiro > <!--注意:url在thmeleaf中需要用@开头-->
<form class="form-sigin" th:action="@{/test}" method="post">

测试编写对应的登录控制器

@PostMapping("/test")
@ResponseBody
public String test(@RequestParam("username")String username,
@RequestParam("password")String password){
System.out.println(username+password);
return "OK!!";
}

添加功能:判断用户密码是否正确

  • 控制器:
@PostMapping("login")
public String login(@RequestParam("username")String username,
@RequestParam("password")String password,
Model model,
HttpSession session){
//判断用户密码是否正确,成功了,登录状态码为200且在session中会有用户名,否则登录状态码为200
if (username.equals("admin") && password.equals("123456")){
session.setAttribute("loginStatus",200);
session.setAttribute("username",username);
//成功了直接重定向到list去获取用户数据
return "redirect:list";
}else{
session.setAttribute("loginStatus",400);
//失败了加上session状态码,然后继续返回到index页面
return "index";
}
} @GetMapping("list")
public String list(){
return "list";
}
  • 模板:
<!--只有当if里面的条件成立了才会显示这段语句-->
<div th:if="${session.loginStatus==400}">
<div class="alert alert-danger" role="alert">用户名或密码错误!!!</div>
</div>

添加功能:当没有登录的时候进入其他页面会自动跳转到登录页面

这是一个拦截器功能,需要创建一个HandleInterceptor类,还有一个配置类

  • HandleInterceptor类
//注意这个配置类必须要放置到IOC容器中去
@Component
public class LoginHandleInterceptor implements HandlerInterceptor {
//把三个方法全部重写,主要是第一个方法,后面的方法可删去
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object loginStatus = request.getSession().getAttribute("loginStatus");
if (loginStatus==null){
//未登录状态
response.sendRedirect("/");
return false;
}else{
if ((Integer) loginStatus == 400){
//登录失败状态
response.sendRedirect("/");
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 { }
}
  • 配置类
@Configuration
public class MyConfig implements WebMvcConfigurer { //视图控制
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
} @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandleInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/","/index","/index.html","/login");
}
}

首页到此为止

下面开始处理list员工列表

先把对应的url想好

  • list-input:(GET) /input (不带参数)

  • input-list: (POST) /saveEmployee(带了name,gender,email,departmentId参数)

  • list-delete: (GET)/delete (带一个对应的employee的id的参数)

  • list-update:(GET) /update(带一个对应的employee的id的参数)

  • update-list:(POST) /updateEmployee(带了email和departmentId的参数)

然后就是直接实现即可

注意:

关键是更新怎么实现:

list界面到input界面-带入对应的员工id的参数,在控制器处加入updateStatus状态码和对应的这个employee的对象,到了input界面则根据updateStatus状态码判断进入update部分用对应的这个employee对象进行手动回显,并且将name和gender设为disabled(隐藏提交id,name,gender),然后在控制器处new一个新对象,把这个新对象用save方法加入到employeeDao中去

get方法怎么携带参数?

两种方式:

  • /employee/1001

    <a th:href="@{/employee/{id}(id=1001)}"></a>
    或者
    <a th:href="@{/employee/{id}(id=${employee.id})}"></a>
  • /employee?id=1001

    <a th:href="@{/employee(id=1001)}"></a>
    或者
    <a th:href="@{/employee(id=${employee.id})}"></a>

怎么让表单不能被使用但又可以提交?

两种方式:

  • readonly:只读模式

    在最后面加上readonly属性即可,但是只有input才有效,seletor没用

    <input class="form-control" type="text" placeholder="Readonly input here…" readonly>
    
    
  • disabled:禁用模式

    在最后面加上disabled属性即可,但是会把要提交的信息也给禁用了,需要另外隐藏提交相关信息

    <input class="form-control" id="disabledInput" type="text" placeholder="Disabled input here..." disabled>

展示最终thmeleaf页面为:

  • list界面
<body class="text-center">
<div class="contaniner">
<div class="row">
<div class="col-md-4">
<h4>【[[${session.username}]]】 sir</h4>
</div>
</div>
<div class="row">
<div class="col-md-4">
<a th:href="@{/input}"><button class="bnt btn-primary">Add Employee</button></a>
</div>
</div>
<div class="row">
<div class="col-md-offset-2 col-md-10">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>name</th>
<th>gender</th>
<th>email</th>
<th>departmentId</th>
<th>departmentName</th>
<th>handle</th>
</tr>
</thead>
<tbody>
<tr th:each="employee:${employees}">
<th th:text="${employee.getId()}"></th>
<th th:text="${employee.getLastName()}"></th>
<div th:if="${employee.getGender()==1}">
<th>男</th>
</div>
<div th:if="${employee.getGender()==0}">
<th>女</th>
</div>
<th th:text="${employee.getEmail()}"></th>
<th th:text="${employee.getDepartment().getDepartmentId()}"></th>
<th th:text="${employee.getDepartment().getDepartmentName()}"></th>
<th> <a th:href="@{/update(id=${employee.getId()})}"><button class="btn btn-danger">alter</button></a>
<!--这个携带参数是用?携带参数,还有一种是比如:/employee/1001携带参数-->
<!---->
<a th:href="@{/delete(id=${employee.getId()})}"><button class="btn btn-primary">delete</button></a>
</th>
</tr>
</tbody>
</table>
</div>
</div>
</div> </body>
  • input界面
<body>
<div class="container"> <!--添加员工界面-->
<div th:if="${updateStatus==null}">
<form class="form-horizontal" th:action="@{/saveEmployee}" method="post">
<h3>添加员工</h3>
<!--name-->
<div class="form-group">
<label for="name" class="col-sm-4 control-label"><strong>Name</strong></label>
<div class="col-sm-4">
<input type="text" name="name" class="form-control" id="name" placeholder="name">
</div>
</div>
<!--gender-->
<div class="form-group">
<label class="col-sm-4 "><strong>Gender</strong></label>
<div class="col-sm-4">
<select name="gender" class="form-control">
<option value="1">男</option>
<option value="0">女</option>
</select>
</div>
</div> <!--email-->
<div class="form-group">
<label for="email" class="col-sm-4 control-label"><strong>Email</strong></label>
<div class="col-sm-4">
<input type="email" name="email" class="form-control" id="email" placeholder="email">
</div>
</div>
<!--department-->
`<div class="form-group">
<label class="col-sm-4 control-label"><strong>Department</strong></label>
<div class="col-sm-4">
<select class="form-control" name="departmentId">
<div th:each="department:${departments}">
<option th:text="${department.getDepartmentId()}"></option>
</div>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success btn-sm">CONFIRM ADD</button>
</div>
</div>
</form>
</div> <!--修改员工界面-->
<div th:if="${updateStatus=='update'}">
<form class="form-horizontal" th:action="@{/updateEmployee}" method="post">
<h3>修改员工</h3>
<input type="hidden" th:value="${updateEmployee.getId()}" name="employeeId">
<input type="hidden" th:value="${updateEmployee.getLastName()}" name="name">
<input type="hidden" th:value="${updateEmployee.getGender()}" name="gender">
<!--name-->
<div class="form-group" readonly>
<label for="updateName" class="col-sm-4 control-label"><strong>Name</strong></label>
<div class="col-sm-4">
<input th:value="${updateEmployee.getLastName()}" type="text" name="name" class="form-control" id="updateName" placeholder="name" disabled>
</div>
</div>
<!--gender-->
<div class="form-group">
<label class="col-sm-4 "><strong>Gender</strong></label>
<div class="col-sm-4">
<div th:if="${updateEmployee.getGender()==1}">
<select th:value="${updateEmployee.getGender()}" name="gender" class="form-control" disabled>
<option value="1">男</option>
<option value="0">女</option>
</select>
</div>
<div th:if="${updateEmployee.getGender()==0}">
<select id="disableInput" th:value="${updateEmployee.getGender()}" name="gender" class="form-control" disabled>
<option value="0">女</option>
<option value="1">男</option>
</select>
</div>
</div>
</div>
<!--email-->
<div class="form-group">
<label for="updateEmail" class="col-sm-4 control-label"><strong>Email</strong></label>
<div class="col-sm-4">
<input th:value="${updateEmployee.getEmail()}" type="email" name="email" class="form-control" id="updateEmail" placeholder="email">
</div>
</div>
<!--department-->
<div class="form-group">
<label class="col-sm-4 control-label"><strong>Department<span style="color: #c0392b;font-weight: 700">(NOW:[[${updateEmployee.getDepartment().getDepartmentId()+"."+updateEmployee.getDepartment().getDepartmentName()}]])</span></strong></label>
<div class="col-sm-4">
<select class="form-control" name="departmentId">
<div th:each="department:${departments}">
<option th:text="${department.getDepartmentId()}"></option>
</div>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success btn-sm">CONFIRM UPDATE</button>
</div>
</div>
</form>
</div>
</div>
</body>

springboot-4-CRUD开发实战的更多相关文章

  1. 小D课堂【SpringBoot】接口Http协议开发实战

    ---恢复内容开始--- ====================2.SpringBoot接口Http协议开发实战 ============================= 1.SpringBoot ...

  2. SpringBoot微服务电商项目开发实战 --- Redis缓存雪崩、缓存穿透、缓存击穿防范

    最近已经推出了好几篇SpringBoot+Dubbo+Redis+Kafka实现电商的文章,今天再次回到分布式微服务项目中来,在开始写今天的系列五文章之前,我先回顾下前面的内容. 系列(一):主要说了 ...

  3. SpringBoot微服务电商项目开发实战 --- api接口安全算法、AOP切面及防SQL注入实现

    上一篇主要讲了整个项目的子模块及第三方依赖的版本号统一管理维护,数据库对接及缓存(Redis)接入,今天我来说说过滤器配置及拦截设置.接口安全处理.AOP切面实现等.作为电商项目,不仅要求考虑高并发带 ...

  4. SpringBoot微服务电商项目开发实战 --- 模块版本号统一管理及Redis集成实现

    上一篇文章总结了基于SpringBoot实现分布式微服务下的统一配置.分环境部署配置.以及服务端模块的分离(每一个提供者就是一个独立的微服务).微服务落地.Dubbo整合及提供者.消费者的配置实现.本 ...

  5. 图书-技术-SpringBoot:《Spring Boot 企业级应用开发实战》

    ylbtech-图书-技术-SpringBoot:<Spring Boot 企业级应用开发实战> Spring Boot 企业级应用开发实战,全书围绕如何整合以 Spring Boot 为 ...

  6. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-10.Springboot2.x用户登录拦截器开发实战

    笔记 10.Springboot2.x用户登录拦截器开发实战     简介:实战开发用户登录拦截器拦截器 LoginInterceptor                  1.实现接口 LoginI ...

  7. SpringBoot:Web开发

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 , 基于atguigu 1.5.x 视频优化 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处 ...

  8. [原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇)

    原文:[原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) .NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) 前言:上一篇文章讲述了一些实现DAL的理论,本 ...

  9. 《精通Spring 4.X企业应用开发实战》读书笔记1-1(IoC容器和Bean)

    很长一段时间关注在Java Web开发的方向上,提及到Jave Web开发就绕不开Spring全家桶系列,使用面向百度,谷歌的编程方法能够完成大部分的工作.但是这种不系统的了解总觉得自己的知识有所欠缺 ...

  10. 11. SpringBoot 之CRUD实例

    SpringBoot静态页路径,可直接通过URL访问的: /META-INF/resources /resources /static /public 而    5. /template 只和模板引擎 ...

随机推荐

  1. Docker系列——Grafana+Prometheus+Node-exporter微信推送(三)

    在之前博文中,已经成功的实现了邮件推送.目前主流的办公终端,就是企业微信.钉钉.飞书.今天来分享下微信推送,我们具体来看. 企业微信 在配置企业微信推送时,需要有微信企业,具体如何注册.使用,另外百度 ...

  2. halcon——缺陷检测常用方法总结(频域空间域结合)

    摘要 缺陷检测是视觉需求中难度最大一类需求,主要是其稳定性和精度的保证.首先常见缺陷:凹凸.污点瑕疵.划痕.裂缝.探伤等. 缺陷检测算法不同于尺寸.二维码.OCR等算法.后者应用场景比较单一,基本都是 ...

  3. 错误档案1:Eclipse自动生成swing窗体代码报错

    目录 前言 错误信息 解决方法 结论 前言 大家好呀,我是 白墨,一个热爱学习与划水的矛盾体. 昨天为了图方便,使用MyEclipse中的swing功能画界面,画完以后发现无法运行,查看源代码发现全报 ...

  4. 【NX二次开发】Block UI 多行字符串

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  5. Django基础之cookie与session

    cookie与session 由来及简介 HTTP协议四大特性 1.基于请求响应 2.基于TCP.IP作用于应用层之上 3.无连接 4.无状态 基于HTTP协议的通信无法记录客户端状态 但是现在很多软 ...

  6. 使用 Docker 部署 Node 应用

    容器将应用与环境打包整合,解决了应用外部依赖的痛点,打包后通过窗口可方便地部署到任意环境,用过就知道很香. 创建示例应用 以 NestJS 为例,先创建一个示例应用. $ npm i -g @nest ...

  7. 终于明白为什么要加 final 关键字了

    在开发过程中,由于习惯的原因,我们可能对某种编程语言的一些特性习以为常,特别是只用一种语言作为日常开发的情况.但是当你使用超过一种语言进行开发的时候就会发现,虽然都是高级语言,但是它们之间很多特性都是 ...

  8. LCD1602液晶显示模块的单片机驱动深入详解之硬件篇

    (本文以HD44780主控芯片的LCD1602为蓝本进行描述,其中的截图也来自HD44780数据手册,用户可自行搜索其datasheet,有部分整理网上的,但绝对要比你看到的要深入得多) 一.接口 L ...

  9. react 的优点

    1. 声明式开发 react 是声明式的开发方式,与之对应的是命令式开发方式.之前用jquery写代码的时候,我们都是直接操作dom,这种我们称为命令式的编程.命令式编程需要我们一点点的告诉dom,它 ...

  10. js笔记4

    1.js数据类型分析 (1)基础类型:string.number.boolean.null.undefined (2)引用类型:object-->json.array... 2.点运算  xxx ...