數據庫准備
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; USE `mybatis`; /*Table structure for table `department` */ CREATE TABLE `department` ( `did` int NOT NULL AUTO_INCREMENT, `departmentName` varchar(20) NOT NULL, PRIMARY KEY (`did`) ) ENGINE=InnoDB AUTO_INCREMENT=106 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `department` */ insert into `department`(`did`,`departmentName`) values (101,'教學部'),(102,'市場部'),(103,'教研部'),(104,'運營部'),(105,'后勤部'); /*Table structure for table `employee` */ CREATE TABLE `employee` ( `id` int NOT NULL AUTO_INCREMENT, `lastName` varchar(20) NOT NULL, `email` varchar(20) NOT NULL, `gender` int NOT NULL, `birth` date DEFAULT NULL, `department` int NOT NULL, PRIMARY KEY (`id`), KEY `did` (`department`), CONSTRAINT `did` FOREIGN KEY (`department`) REFERENCES `department` (`did`) ) ENGINE=InnoDB AUTO_INCREMENT=1015 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `employee` */ insert into `employee`(`id`,`lastName`,`email`,`gender`,`birth`,`department`) values (1001,'AA','121456qq.com',1,'2021-03-09',101),(1003,'BB','124561@qq.com',0,'2021-05-03',105),(1005,'zhangsan','1210418430@qq.com',1,'2021-07-04',102),(1006,'zhangsan','1210418430@qq.com',1,'2021-07-04',102),(1009,'zhangsans','a123456yy@qq.com',1,'2000-02-02',102),(1010,'20210704','14565430@qq.com',0,'2000-02-02',105),(1011,'djfihasf\'','1214546@qq.com',0,'2000-02-02',103),(1014,'sadasdsad','456430@qq.com',0,'2000-02-02',103); /*Table structure for table `user` */ CREATE TABLE `user` ( `id` int NOT NULL, `name` varchar(20) DEFAULT NULL, `pwd` varchar(30) DEFAULT NULL, `perms` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `user` */ insert into `user`(`id`,`name`,`pwd`,`perms`) values (1,'java','java','user:add'),(2,'1210','1210','user:add'),(3,'wsad','1210','user:add'),(5,'c++','1210','user:add'),(6,'張三','1210','user:update'),(7,'張思','1210','user:update'),(8,'李四','1210','user:update'),(9,'root','123','user:update');
基本環境搭建
新建一個Springboot項目,導入pom依賴
<?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>2.5.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.myproject</groupId> <artifactId>springbootproject01</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springbootproject01</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <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> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
建立基本結構和配置框架
application.properties
spring.thymeleaf.cache=false spring.messages.basename=i18n.login spring.mvc.format.date=yyyy-MM-dd spring.datasource.username=root spring.datasource.password=1234 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.type=com.alibaba.druid.pool.DruidDataSource mybatis.type-aliases-package=com.myproject.pojo mybatis.mapper-locations=classpath:mybatis/*.xml
package
com.myproject.config
SecurityConfigTest
com.myproject.controller
EmployeeController
com.myproject.mapper
DepartmentMapper
DepartmentMapperImpl
EmployeeMapper
EmployeeMapperImpl
UserMapper
UserMapperImpl
com.myproject.pojo
Department
Employee
EmployeeWeb
Users
com.myproject.service
DepartmentService
DepartmentServiceImpl
EmployeeService
EmployeeServiceImpl
MyUserDetailsService
UserService
UserServiceImpl
resources
mybatis
DepartmentMapper.xml
EmployeeMapper.xml
UserMapper.xml
static(前端資源)
templates(前端資源)
安全管理框架(SpringSecurity)
MyUserDetailsService.java主要用接收傳遞用戶名密碼。
package com.myproject.service; import com.myproject.mapper.UserMapper; import com.myproject.pojo.Users; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import java.util.List; @Component @Service("userDetailsService") public class MyUserDetailsService implements UserDetailsService { /** * 實現UserDetailsService中的loadUserByUsername方法 * loadUserByUsername會從表單中獲取name為"username"和"password"的字段, * 實現此方法會傳入username來讓我們驗證,即我們從數據庫中查詢這個用戶是否存在, * 然后將查詢到的密碼傳給BCryptPasswordEncoder對象,這個對象會自動幫我們去驗證密碼正確 * BCryptPasswordEncoder采用SHA-256 +隨機鹽+密鑰對密碼進行加密,這個方法不能傳入明文密碼 */ @Autowired UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Users user = userMapper.queryUserByName(username);//從數據庫獲取User對象 if (user==null){//如果用戶並不存在則會拋出異常 throw new UsernameNotFoundException("用戶名不存在"); } List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("role"); //設置用戶角色 // 我們可以從User的構造器中看到,User中需要傳入三個值,即用戶名,加密的密碼和用戶角色 // public User(String username, String password, Collection<? extends GrantedAuthority> authorities) return new User(user.getName() ,new BCryptPasswordEncoder().encode(user.getPwd()),role); //這個User是package org.springframework.security.core.userdetails下的User,並不是我們的實體類對象。 } }
SecurityConfigTest.java主要設置用戶權限,即授權。
package com.myproject.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import sun.security.util.Password; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(password()); //在 Spring Security 中,用來處理身份認證的類是 AuthenticationManager,我們也稱之為認證管理器。 //而AuthenticationManagerBuilder用來生成一個AuthenticationManager, //passwordEncoder需要一個BCryptPasswordEncoder,即下面這個方法生成一個BCryptPasswordEncoder返回給AuthenticationManagerBuilder } @Bean PasswordEncoder password(){ return new BCryptPasswordEncoder();//生成一個BCryptPasswordEncoder創個上面的passwordEncoder } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/")//設置登錄頁面 .loginProcessingUrl("/user/login")//表單傳遞的地址,即action .defaultSuccessUrl("/emps").permitAll()//登錄成功跳轉地址 .and().authorizeRequests().antMatchers("/").permitAll()//放行的頁面,一般登錄頁面需要放行 .anyRequest().authenticated()//任何請求都必須經過身份驗證,否則返回401響應 .and().csrf().disable()//Cross-site request forgery跨站請求偽造,也被稱為“One Click Attack”或者Session Riding, // 通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。為了防止跨站提交攻擊,通常會配置csrf。但也會影響性能,可自由選擇開啟或關閉 ; http.logout().logoutUrl("/user/logout")//注銷 .logoutSuccessUrl("/").permitAll(); } }
EmployeeController.java
package com.myproject.controller; import com.myproject.mapper.DepartmentMapperImpl; import com.myproject.pojo.Department; import com.myproject.pojo.Employee; import com.myproject.pojo.EmployeeWeb; import com.myproject.service.DepartmentServiceImpl; import com.myproject.service.EmployeeServiceImpl; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; import java.util.*; @Controller public class EmployeeController { @Autowired private EmployeeServiceImpl employeeService; @Autowired private DepartmentServiceImpl departmentService; /** * * @param model * @return * 這個方法就是登錄后要跳轉的Servlet,這個方法會拿到全部的員工信息,然后返回給list.html頁面。 */ @RequestMapping("/emps") public String list(Model model){ List<Employee> employees = employeeService.queryAll(); List<EmployeeWeb> list=new ArrayList(); for (int i=0;i<employees.size();i++){ EmployeeWeb employeeWeb=new EmployeeWeb(); List<Department> depAll = departmentService.getDepAll(); int department = employees.get(i).getDepartment(); int id = employees.get(i).getId(); String lastName = employees.get(i).getLastName(); int gender = employees.get(i).getGender(); String email = employees.get(i).getEmail(); Date birth = employees.get(i).getBirth(); for (int j=0;j<depAll.size();j++){ int did = depAll.get(j).getDid(); if (did==department){ employeeWeb.setDepartment(depAll.get(j)); } } employeeWeb.setId(id); employeeWeb.setLastName(lastName); employeeWeb.setBirth(birth); employeeWeb.setEmail(email); employeeWeb.setGender(gender); list.add(employeeWeb); } model.addAttribute("emps",list); for (EmployeeWeb employeeWeb : list) { System.out.println(employees); } return "emp/list"; } /** * * @param model * @return * 這個方法會獲取獲得所有的部門對象,然后傳給add頁面,因為部門選項需要所有的部門信息。 */ @GetMapping("/emp") public String toAllpage(Model model){ List<Department> depList = departmentService.getDepAll(); model.addAttribute("departments",depList); return "emp/add"; } /** * * @param employee * @return * 這個方法會從add頁面獲取需要添加的員工信息,然后將數據傳回數據庫,完成后悔重定向到所有成員的列表頁面。 */ @PostMapping("/emp") public String addEmp(Employee employee){ System.out.println(employee); Boolean aBoolean = employeeService.saveEmp(employee); System.out.println(aBoolean); return "redirect:/emps"; } /** * * @param id * @param model * @return * 這個方法是更新員工信息跳轉的Servlet,這個方法需要先得到需要更新的員工id, * 然后傳回到更新頁面,同時這個方法也需要查詢出全部的部門信息,傳回給跟新頁面, * 同樣是部門選項需要全部的部門信息,然后跳轉到更新頁面。 */ @GetMapping("/toUpdate/{id}") public String toUpdate(@PathVariable("id")Integer id, Model model){ System.out.println("toUpdate"); Employee employee = employeeService.queryById(id); model.addAttribute("employee",employee); //查詢所有部門信息 List<Department> depAll = departmentService.getDepAll(); model.addAttribute("departments",depAll); return "emp/update"; } /** * * @param employee * @return * 這個方法會從前端會的一個員工新的信息,完成員工的信息更新,然后重定向到所有成員的列表頁面。 */ @PostMapping("/updateUser") public String Update(Employee employee){ employeeService.saveEmp(employee); return "redirect:/emps"; } /** * * @param id * @return * 這個方法會從前端得到一個員工id,執行刪除,然后重定向到所有成員的列表頁面。 */ @GetMapping("/delemp/{id}") public String delemp(@PathVariable("id")Integer id){ employeeService.deleteEmp(id); return "redirect:/emps"; } //如果登錄的用戶沒有權限執行某個操作,則會跳轉到此方法,該方法未完成。 @RequestMapping("/noauth") @ResponseBody public String unauthorized(){ return "未授權無法訪問此頁面"; } //已被SpringSecurity解決 // @RequestMapping("/user/logout") // public String logOut(HttpSession session){ // session.invalidate(); // return "redirect:/index.html"; // } }
頁面
總結
這個項目是采用SpringBoot開發的,SpringBoot相較於Spring省略了很多配置,取而代之的是通過注解來完成IOC,極大地簡化了開發過程,除了SpringBoot,這個項目還采用了SpringSecurity來完成用戶登錄的授權和認證。
項目鏈接:https://gitee.com/coopermini/employee-management-system