1、数据库表
(1)employee表
(2)department表
2、目录结构
(1)java根目录
(2)资源文件目录
3、maven依赖
需要导入thymeleaf启动器 、web启动器、mybatis启动器、jdbc启动器、mysql启动器已经Lombok依赖,这里之前springboot版本是3.2.2但是出现了应该是mybatis版本不兼容问题,所以降为3.1.2。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhangxin</groupId>
<artifactId>springboot-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-web</name>
<description>springboot-web</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- thymeleaf启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!-- jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- lombok-->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4、pojo
(1)Department类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
private Integer dId;
private String dName;
}
(2)Employee类
@NoArgsConstructor
@Data
public class Employee {
private Integer eId;
private String eName;
private String email;
private Integer gender;//0女 1男
private Integer dId;
private Date birth;
//这里选择让birth获取当前时间赋值
public Employee(Integer eId, String eName, String email, Integer gender, Integer dId) {
this.eId = eId;
this.eName = eName;
this.email = email;
this.gender = gender;
this.dId = dId;
birth=new Date();
}
}
5、mapper(dao)
作为持久层(model)负责和数据库交互,直接和数据库进行数据交换。
@mapper注解可以自动为接口生成对应实现类并注入容器,所以@Repository注解的作用主要还是标识作用,如果觉得一个个添加@mapper注解麻烦可以使用@MapperScan(“”)注解扫描mapper接口所在的包。
其实使用了@Mapper就可以不用写mpaaer.xml文件了,但是这样就需要sql写在java代码中,使用用@Select、@insert注解,具体怎么写sql还是看个人习惯。
(1)DepartmentMapper
@Repository
@Mapper
public interface DepartmentMapper {
// 获取所有的部门信息
Collection<Department> getDepartments();
}
(2)EmployeeMapper
@Repository
@Mapper
public interface EmployeeMapper {
// 添加
void addEmployee(Employee employee);
// 更新
void updateEmployee(Employee employee);
// 查询全部
Collection<Employee> getAllEmployee();
// 通过id
Employee getEmployeeById(Integer id);
// 删除员工
void deleteEmployeeById(Integer id);
}
6、service
作为业务层调用dao层,里面可以添加一些具体的业务,一般是规定一个service接口serviceImp继承并调用对应的dao层,使用@service注解把serviceImp注入容器并且表示这是service层。
(1)DepartmentService
public interface DepartmentService {
// 获取所有的部门信息
Collection<Department> getDepartments();
// 获取id和name的mapper
public HashMap<Integer,String> getIdNameMap();
}
(2)DepartmentServiceImp
这里因为直接用sql语句很难查询出一个id和name的HashMap所以我选择在业务层处理这个HashMap,这个HashMap的作用主要是在页面上可以根据dId查询出dName。
@Service
public class DepartmentServiceImp implements DepartmentService{
@Autowired
private DepartmentMapper departmentMapper;
@Override
public Collection<Department> getDepartments() {
return departmentMapper.getDepartments();
}
@Override
public HashMap<Integer, String> getIdNameMap() {
Collection<Department> departments = departmentMapper.getDepartments();
HashMap<Integer, String> map=new HashMap<>();
departments.forEach(department -> {
map.put(department.getDId(),department.getDName());
});
return map;
}
(3)EmployeeService
public interface EmployeeService {
// 添加
void addEmployee(Employee employee);
// 更新
void updateEmployee(Employee employee);
Collection<Employee> getAllEmployee();
// 通过id
Employee getEmployeeById(Integer id);
// 删除员工
void deleteEmployeeById(Integer id);
}
(4)EmployeeServiceImp
@Service
public class EmployeeServiceImp implements EmployeeService{
@Autowired
private EmployeeMapper employeeMapper;
@Override
public void addEmployee(Employee employee) {
employeeMapper.addEmployee(employee);
}
@Override
public void updateEmployee(Employee employee) {
employeeMapper.updateEmployee(employee);
}
@Override
public Collection<Employee> getAllEmployee() {
return employeeMapper.getAllEmployee();
}
@Override
public Employee getEmployeeById(Integer id) {
return employeeMapper.getEmployeeById(id);
}
@Override
public void deleteEmployeeById(Integer id) {
employeeMapper.deleteEmployeeById(id);
}
}
7、controller
Controller 在 spring 中代表的是控制层,是将访问者请求进行分发调用不同函数,来控制获取请求参数以及返回service层处理完的数据给访问者的层面。它在 spring 中必须在 Controller 类前添加 @Controller 注解,以注入容器中,并发挥作用。
(1)LoginController
负责登录验证和注销,我这里就是密码判断一下是否是“123”即可,session.invalidate()就是销毁session下次登录需要重新创建。
@Controller
public class LoginController {
@RequestMapping(value = "/user/login")
public String login(@RequestParam("username") String username, @RequestParam("password")String password,
Model model, HttpSession session){
if(!StringUtils.isEmpty(username)&&password.equals("123")){
session.setAttribute("loginUser",username);
/**
* 通过就重定向到主页(后面重写了WebMvcConfigurer的addViewControllers方法,
* 绑定了主页和main.html,实际上是不存在main.html的)
*/
return "redirect:/main.html";
}else{
/**
* 不通过就返回登录页,返回错误信息
*/
model.addAttribute("err","信息错误!");
return "index";
}
}
// 注销
@RequestMapping("/user/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:/";
}
}
(2)MyController
自定义404界面,@RequestMapping固定为"/test",在输入一些不存在的页面的时候就可以跳到你自定义的404.html了
@Controller
public class MyController {
@RequestMapping("/test")
public String test(){
return "error/404";
}
}
(3)EmployeeController
视图跳转的主要controller。
@Controller
public class EmployeeController {
@Resource
private EmployeeService employeeService;
@Resource
private DepartmentService departmentService;
@RequestMapping("/emp")
public String list(Model model){
model.addAttribute("emps",employeeService.getAllEmployee());
model.addAttribute("dmap",departmentService.getIdNameMap());
return "emp/list";
}
@GetMapping("/addEmp")
public String toAddPage(Model model){
model.addAttribute("deps",departmentService.getDepartments());
return "emp/addEmp";
}
@PostMapping("/addEmp")
public String addEmp(Employee employee){
employeeService.addEmployee(employee);
return "redirect:emp";
}
@GetMapping("/updateEmp")
public String toUpdatePage(Model model,Integer id ){
model.addAttribute("deps",departmentService.getDepartments());
model.addAttribute("emp",employeeService.getEmployeeById(id));
return "emp/updateEmp";
}
@PostMapping("/updateEmp")
public String updateEmp(Employee employee){
employeeService.updateEmployee(employee);
return "redirect:emp";
}
@RequestMapping("/deleteEmp")
public String deleteEmp(Integer id){
employeeService.deleteEmployeeById(id);
return "redirect:emp";
}
}
8、Mapper.xml
编写mapper接口类对应的sql语句,注意resultType表示返回值类型,parameterType表示参数类型。
(1)DepartmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace要和一个接口的全类名一致-->
<mapper namespace="com.zhangxin.springbootweb.mapper.DepartmentMapper">
<!--Collection<Department> getDepartments();-->
<select id="getDepartments" resultType="Department" >
select * from department;
</select>
</mapper>
(2)EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace要和一个接口的全类名一致-->
<mapper namespace="com.zhangxin.springbootweb.mapper.EmployeeMapper">
<!-- void addEmployee(Employee employee);-->
<insert id="addEmployee" parameterType="Employee">
insert into employee
values(null,#{eName},#{email},#{gender},#{dId},#{birth});
</insert>
<!-- void updateEmployee(Employee employee);-->
<update id="updateEmployee" parameterType="Employee">
update employee
set e_name=#{eName},email=#{email},gender=#{gender},d_id=#{dId},birth=#{birth}
where e_id=#{eId};
</update>
<!-- Collection<Employee> getAllEmployee();-->
<select id="getAllEmployee" resultType="Employee">
select * from employee;
</select>
<!-- Employee getEmployeeById(Integer id);-->
<select id="getEmployeeById" resultType="Employee" parameterType="int">
select * from employee where e_id=#{id};
</select>
<!-- void deleteEmployeeById(Integer id);-->
<delete id="deleteEmployeeById" parameterType="int">
delete from employee where e_id=#{id};
</delete>
</mapper>
9、config
关系项目的整体配置类。
(1)登录拦截器(HandlerInterceptor)
对应没有登录但访问页面行为进行拦截,通过是否有loginUser判断是否完成登录,没有完成登录就返回登录页并且添加错误信息。
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 检查session,后面有登录页面的放行
Object loginUser = request.getSession().getAttribute("loginUser");
if(loginUser==null){
request.setAttribute("err","无权限,请先登录");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else return true;
}
}
(2)WebMvcConfigurer
可以自定义拦截器、消息转换器、视图跳转控制器等配置,它的拦截器和HandlerInterceptor配置的拦截器一个效果。
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocalResolver();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/user/login" ,"/css/**","/js/**","/img/**","/");
}
}
- addViewControllers是视图跳转控制器可以减少controller的代码量,比如上面的 addViewControllers执行效果分别是
跳转到"/“等效于"index”、跳转到"/index.html"等效于"index"、跳转到"/main.html"等效于"dashboard"。
注意:setViewName对应的是@RequestMapping中的地址。 - localeResolver是注入一个关于国际化的Bean,其实写在任意@Configuration标识的类都行与WebMvcConfigurer本身无太大关系
- addInterceptors是拦截器其中registry.addInterceptor()添加一个拦截器
addPathPatterns(“/**”)这里指的是拦截所有请求
excludePathPatterns()表示放行的请求地址,就像之前的登录拦截器实际上登录页面session也没有登录者所以应该被拦截,但是这里对登录的页面进行了放行。
(3)国际化
在项目开发过程中,可能会针对不同的国家的用户提供不同的视图,如针对美国用户提供一个视图,针对中国用户提供一个视图,这时候就需提供在同个页面上,能切换不同的语言,而LocaleResolver能够帮我们实现这种切换。
resolveLocale()方法获取前端传过来的参数,根据参数判断国际地区,上面的MyConfig类已经实现了MyLocalResolver的注入。
//地址解析
public class MyLocalResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
// 获取参数
String l = request.getParameter("l");
Locale locale = Locale.getDefault();//获取默认
if(!StringUtils.isEmpty(l)){//非空
String[] s = l.split("_");
locale=new Locale(s[0],s[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
前端对应的国际化的标签
<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>
i18n国际化资源文件
默认:login.properties
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
中文:login_zh.properties
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
英文:login_en_us.properties
login.btn=sign in
login.password=Password
login.remember=Remember me
login.tip=Please sign in
login.username=username
需要国际化的页面
Thymeleaf动态展示国际化页面,使用 th:placeholder="#{ }"绑定国际化的资源文件里的元素。
<input name="username" type="text" th:placeholder="#{login.username}">
10、application.yaml
springboot的核心配置文件。
#规定端口
server:
port: 8080
spring:
thymeleaf:
#关闭thymeleaf缓存
cache: false
messages:
#自定义的国际化配置引入
basename: i18n.login
mvc:
format:
#设置日期格式
date: yyyy-MM-dd
#数据库信息
datasource:
username: root
password: 1234567
url: jdbc:mysql://localhost:3306/spring_boot_blog?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
configuration:
#下划线命名转化为驼峰命名
map-underscore-to-camel-case: true
#导入需要识别的类的包,即数据库表对应的实体类pojo
type-aliases-package: com.zhangxin.springbootweb.pojo
#导入mapper所在的包(写sql的xml)
mapper-locations: classpath:mapper/*.xml