简单员工管理系统(springBoot+springSecurity)

员工管理系统(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')">
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
大部分Java应用都是Web应用,展现层是Web应用不可忽略的重要环节。Spring为展现层提供了一个优秀的Web框架——Spring MVC。和众多其它Web框架一样,它基于MVC设计理念,此外,由于它采用了松散耦合可插拔组件结构,具有比其它MVC框架更多的扩展性和灵活性。 Spring MVC框架围绕DispatcherServlet这个核心展开,DispatcherServlet的作用是截获请求并组织一系列组件共同完成请求的处理工作。 JavaServer Faces (JSF) 是一种用于构建 Web 应用程序的新标准 Java 框架。它提供了一种以组件为中心来开发 Java Web 用户界面的方法,从而简化了开发。JavaServer Faces 还引起了广大 Java/Web 开发人员的兴趣。“企业开发人员”和 Web 设计人员将发现 JSF 开发可以简单到只需将用户界面 (UI) 组件拖放到页面上,而“系统开发人员”将发现丰富而强健的 JSF API 为他们提供了无与伦比的功能和编程灵活性。JSF 还通过将良好构建的模型-视图-控制器 (MVC) 设计模式集成到它的体系结构中,确保了应用程序具有更高的可维护性。最后,由于 JSF 是通过 Java Community Process (JCP) 开发的一种 Java 标准,因此开发工具供应商完全能够为 JavaServer Faces 提供易于使用的、高效的可视化开发环境。 ① 整个过程开始于客户端发送一个HTTP请求; ② DispatcherServlet接收这个请求后,并将请求的处理工作委托给具体的处理器(Handler),后者负责处理请求执行相应的业务逻辑。在这之前,DispatcherServlet必须能够凭借请求信息(URL或请求参数等)按照某种机制找到请求对应的处理器,DispatcherServlet是通过垂询HandlerMapping完成这一工作的; ③ 当DispatcherServlet从HandlerMapping中得到当前请求对应的处理器后,它就将请求分派给这个处理器。处理器根据请求的信息执行相应的业务逻辑,一个设计良好的处理器应该通过调用Service层的业务对象完成业务处理,而非自己越俎代庖。 Spring提供了丰富的处理器类型,在真正处理业务逻辑前,有些处理器会事先执行两项预处理工作: 1)将HttpServletRequest请求参数绑定到一个POJO对象中; 2)对绑定了请求参数的POJO对象进行数据合法性校验; ④ 处理器完成业务逻辑的处理后将返回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名和渲染视图时需要用到的模型数据对象; ⑤ 由于ModelAndView中包含的是视图逻辑名,DispatcherServlet必须知道这个逻辑名对应的真实视图对象,这项视图解析的工作通过调用ViewResolver来完成; ⑥ 当得到真实的视图对象后,DispatcherServlet将请求分派给这个View对象,由其完成Model数据的渲染工作; ⑦ 最终客户端得到返回的响应,这可能是一个普通的HTML页面,也可能是一个Excel电子表格、甚至是一个PDF文档等不一而足的视图形式,Spring的视图类型是异常丰富和灵活的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值