员工管理系统(spring boot)
A. 新建一个SpringBoot项目
选择配件时勾选SpringWeb和Thymeleaf
导入依赖pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
B. 导入静态资源
首先创建不存在的静态资源目录public和resources
将html静态资源放置templates目录下
将css、img、js等静态资源放置static目录下
C.创建数据库
-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
`id` int NOT NULL AUTO_INCREMENT,
`departmentName` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of department
-- ----------------------------
INSERT INTO `department` VALUES ('1', '技术部');
INSERT INTO `department` VALUES ('2', '市场部');
INSERT INTO `department` VALUES ('3', '调研部');
INSERT INTO `department` VALUES ('4', '后勤部');
INSERT INTO `department` VALUES ('5', '运营部');
-- ----------------------------
-- Table structure for employee
-- ----------------------------
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int NOT NULL AUTO_INCREMENT,
`lastName` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`email` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`gender` int DEFAULT NULL,
`did` int DEFAULT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `did` (`did`),
CONSTRAINT `did` FOREIGN KEY (`did`) REFERENCES `department` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of employee
-- ----------------------------
INSERT INTO `employee` VALUES ('1', 'zsr', '1234@qq.com', '1', '1', '2021-02-18');
INSERT INTO `employee` VALUES ('2', 'lyr', '1345@qq.com', '1', '2', '2021-02-18');
INSERT INTO `employee` VALUES ('3', 'gcc', '1345@qq.com', '0', '3', '2021-02-18');
INSERT INTO `employee` VALUES ('4', 'zyx', '1345@qq.com', '1', '4', '2021-02-18');
INSERT INTO `employee` VALUES ('5', 'zch', '1345@qq.com', '1', '5', '2021-02-18');
INSERT INTO `employee` VALUES ('14', '112222', '690433091@qq.com', '1', '1', '2020-02-17');
INSERT INTO `employee` VALUES ('15', '1111', '690433091@qq.com', '1', '1', '2021-02-18');
INSERT INTO `employee` VALUES ('17', 'aaa', '690433091@qq.com', '0', '3', '2021-02-19');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
`perms` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'datou', '999999', 'vip2');
INSERT INTO `user` VALUES ('2', 'admin', '123456', 'vip3');
INSERT INTO `user` VALUES ('3', 'dawei', '123890', 'vip1');
INSERT INTO `user` VALUES ('4', 'Tom', '123456', 'vip1');
INSERT INTO `user` VALUES ('5', 'marry', '123456', 'vip1');
INSERT INTO `user` VALUES ('6', 'Tim', '123456', 'vip1');
D.创建数据库实体类
在主程序同级目录下新建pojo包,用来存放实体类
在pojo包下创建一个部门表Department和一个员工表Employee和一个用户表User
部门表:
//部门表
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Department {
private Integer id;
private String departmentName;
}
员工表:
//员工表
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender;//0:女 1:男
private int did;
private Department department;
private Date date;
}
用户表:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
private String perms;
}
E.编写dao层
在主程序同级目录下新建dao包
然后分别编写departmentMapper和employeeMapper,还有userMapper
@Mapper
@Repository
public interface departmentMapper {
@Select("select * from department")
public List<Department> getAllDepartment();
@Select("select * from department where id = #{id}")
public Department getDepartmentById(@Param("id") int id);
}
@Mapper
@Repository
public interface employeeMapper {
@Insert("insert into employee values(#{id},#{lastName},#{email},#{gender},#{did},sysdate())")
public int addEmployee(Employee employee);
public List<Employee> getAllEmployees();
public Employee getEmployeeById(@Param("id") int id);
@Delete("delete from employee where id = #{id}")
public int deleteEmployeeById(@Param("id")int id);
// @Update("update employee set lastName = #{lastName},email = #{email},gender = #{gender}," +
// "did = #{did},date = sysdate() where id = #{id}")
public int updateEmployee(Employee employee);
}
@Mapper
@Repository
public interface userMapper {
@Select("select * from springboot.user where name=#{username}")
public User getUser(@Param("username") String username);
}
在rescources目录下新建mapper包
然后编写mybatis.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">
<mapper namespace="com.example.dao.employeeMapper">
<resultMap id="emplMap" type="Employee">
<result property="id" column="eid"></result>
<result property="lastName" column="ename"></result>
<result property="email" column="eemail"></result>
<result property="gender" column="egender"></result>
<result property="date" column="edate"></result>
<!-- <result property="did" column="edid"></result>-->
<association property="department" javaType="Department">
<result property="id" column="edid"></result>
<result property="departmentName" column="dname"></result>
</association>
</resultMap>
<select id="getEmployeeById" resultMap="emplMap">
select e.id eid,e.lastName ename,e.email eemail,e.did edid,
e.gender egender,e.date edate,d.departmentName dname
from employee e,department d
where e.id = #{id} and e.did = d.id
</select>
<select id="getAllEmployees" resultMap="emplMap">
select e.id eid,e.lastName ename,e.email eemail,e.did edid,
e.gender egender,e.date edate,d.departmentName dname
from employee e,department d
where e.did = d.id
order by eid
</select>
<!-- set lastName = #{lastName},email = #{email},gender = #{gender},did = #{did},date = sysdate()-->
<update id="updateEmployee" parameterType="Employee">
update employee
<set>
<if test="#{lastName}!=null">lastName = #{lastName},</if>
<if test="#{email}!=null">email = #{email},</if>
<if test="#{gender}">gender = #{gender},</if>
<if test="#{did}!=null">did = #{did},</if>
<if test="#{date}!=null">date = #{date}</if>
</set>
where id = #{id}
</update>
</mapper>
在application.yml 文件中配置datasource信息
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
type-aliases-package: com.example.pojo
mapper-locations: classpath:mapper/*.xml
F.编写service层
在主程序同级目录下新建service包
然后分别编写deptServiceImpl和emplServiceImpl
@Service
public class deptServiceImpl {
@Autowired
private departmentMapper mapper;
public List<Department> getAllDepartment(){
return mapper.getAllDepartment();
}
public Department getDepartmentById(int id){
return mapper.getDepartmentById(id);
}
}
@Service
public class emplServiceImpl {
@Autowired
public employeeMapper emplMapper;
public Employee getEmployeeById(int id){
return emplMapper.getEmployeeById(id);
}
public int addEmployee(Employee employee){
return emplMapper.addEmployee(employee);
}
public List<Employee> getAllEmployees(){
return emplMapper.getAllEmployees();
}
public int deleteEmployeeById(int id){
return emplMapper.deleteEmployeeById(id);
}
public int updateEmployee(Employee employee){
return emplMapper.updateEmployee(employee);
}
}
G.编写controller层
在主程序同级目录下新建controller包
然后分别编写EmployeeController
@Controller
public class EmployeeController {
@Autowired
private emplServiceImpl service;
@Autowired
private deptServiceImpl dept;
@RequestMapping("/emps")
public String list(Model model) {
List<Employee> allEmployees = service.getAllEmployees();
model.addAttribute("employees",allEmployees);
return "emp/list";//返回到list页面
}
@RequestMapping("/toAdd")
public String add(Model model) {
//查出所有的部门信息,添加到departments中,用于前端接收
Collection<Department> departments = dept.getAllDepartment();
model.addAttribute("departments", departments);
return "emp/add";//返回到添加员工页面
}
@RequestMapping("/add")
public String addEmp(Employee employee) {
service.addEmployee(employee);
return "redirect:/emps";//重定向到/emps,刷新列表,返回到list页面
}
@RequestMapping("/edit")
public String updateEmp(Employee employee) {
service.updateEmployee(employee);
return "redirect:/emps";//重定向到/emps,刷新列表,返回到list页面
}
//restful风格接收参数
@RequestMapping("/toEdit/{id}")
public String edit(@PathVariable("id") int id, Model model) {
//查询指定id的员工,添加到empByID中,用于前端接收
Employee employeeByID = service.getEmployeeById(id);
model.addAttribute("empByID", employeeByID);
//查出所有的部门信息,添加到departments中,用于前端接收
Collection<Department> departments = dept.getAllDepartment();
model.addAttribute("departments", departments);
return "/emp/update";//返回到编辑员工页面
}
@RequestMapping("/delete/{id}")
public String delete(@PathVariable("id") int id){
service.deleteEmployeeById(id);
return "redirect:/emps";//重定向到/emps,刷新列表,返回到list页面
}
}
H.自定义mvc配置
在主程序同级目录下新建config包
然后分别编写MyMvcConfig类实现登录页面国际化以及重写视图解释器
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/begin.html").setViewName("begin");
registry.addViewController("/toLogin").setViewName("begin");
registry.addViewController("/main.html").setViewName("dashboard");
}
//自定义的国际化组件生效
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
}
页面国际化功能实现
resources目录下新建i18n包,在该包内新建以下三个文件
login.properties
login.tip=请登录
login.password=密码
login.remember=记住我
login.btn=登录
login.username=用户名
login_en_US.properties
login.tip=Please sign in
login.password=password
login.remember=remember me
login.btn=login
login.username=username
login_zh_CN.properties
login.tip=请登录
login.password=密码
login.remember=记住我
login.btn=登录
login.username=用户名
在config包下创建MyLocaleResolver 类
public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
//获取请求中的国际化参数
String language = request.getParameter("l");
//默认的地区
Locale locale = Locale.getDefault();
//如果请求的链接参数不为空,携带了国际化参数
if (!StringUtils.isEmpty(language)) {
String[] split = language.split("_");//zh_CN(语言_地区)
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
在MyMvcConfig类中注册bean
//自定义的国际化组件生效
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
修改对应登录信息页面
<form class="form-signin" th:action="@{/login}" method="post">
<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}"></h1>
<p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
<label class="sr-only"></label>
<input type="text" name="username" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only"></label>
<input type="password" name="password" class="form-control" th:placeholder="#{login.password}" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" th:text="#{login.remember}" name="remember">
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}"></button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<!--这里传入参数不需要使用?使用key=value-->
<a class="btn btn-sm" th:href="@{/begin.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/begin.html(l='en_US')}">English</a>
</form>
最后在application.yml文件中重写配置信息
spring.messages.basename: i18n.login
I.采用springSecurity框架
用springSecurity框架简化登录认证授权功能
在config包下编写securityConfig类
@EnableWebSecurity
public class securityConfig extends WebSecurityConfigurerAdapter {
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll();
// .antMatchers("/emps/**").hasRole("vip1")
// .antMatchers("/toAdd/**").hasRole("vip2")
// .antMatchers("/toEdit/**").hasRole("vip3");
//开启自动配置的登录功能:如果没有权限,就会跳转到登录页面!
// /login 请求来到登录页
// /login?error 重定向到这里表示登录失败
http.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.loginPage("/toLogin")
.loginProcessingUrl("/login"); // 登陆表单提交请求
//开启自动配置的注销的功能
// /logout 注销请求
// .logoutSuccessUrl("/"); 注销成功来到首页
http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
http.logout().logoutSuccessUrl("/");
//记住我
http.rememberMe().rememberMeParameter("remember");
}
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
//Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
//要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
//spring security 官方推荐的是使用bcrypt加密方式。
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("datou").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
}
}
项目到此完成
扩展
不用springSecurity框架,可以自定义拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("user");
if(user==null){
request.setAttribute("msg","请先登录");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
return true;
}
}
}
在MyMvcConfig类中重写addInterceptors方法
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.html", "/", "/login", "/css/**", "/js/**", "/img/**");
}
springSecurity实现不同等级用户隐藏不同内容
<ul class="navbar-nav px-3" sec:authorize="!isAuthenticated()">
<li class="nav-item text-nowrap">
<a class="nav-link" th:href="@{/toLogin}">Sign in</a>
</li>
</ul>
<ul class="navbar-nav px-3" sec:authorize="isAuthenticated()">
<li class="nav-item text-nowrap">
<a class="nav-link" th:href="@{/logout}">Sign out</a>
</li>
</ul>
<li class="nav-item" sec:authorize="hasRole('vip1')">