发布

搭建项目环境

创建项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zhWft6MC-1620146254227)(images/image-20191210110811873.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gtilGJeT-1620146254228)(images/image-20191210111150211.png)]

pom.xml

<?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.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.bdqn</groupId>
    <artifactId>erp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>erp</name>
    <description>进销存管理系统</description>

    <properties>
        <java.version>1.8</java.version>
        <mybatisplus.version>3.2.0</mybatisplus.version>
        <shiro.version>1.4.1</shiro.version>
        <druid.version>1.1.18</druid.version>
        <log4j.version>1.2.17</log4j.version>
        <hutool.version>4.6.6</hutool.version>
        <lang3.version>3.9</lang3.version>
    </properties>

    <dependencies>
        <!-- spring boot 启动器依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 内置tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- thymeleaf模板 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- mybatis plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>

        <!-- 引入shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!--shrio和thymeleaf集成的扩展依赖,为了能在页面上使用xsln:shrio的标签 -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <!-- 引入druid的依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>


        <!--hutool-all -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

        <!-- fast json -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
        </dependency>

        <!--  mybatisplus代码生成器依赖  -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.29</version>
        </dependency>
        <dependency>
            <groupId>com.ibeetl</groupId>
            <artifactId>beetl</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <!-- common-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${lang3.version}</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

#加载驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接路径
spring.datasource.url=jdbc:mysql://localhost:3306/erp?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
#数据库用户名
spring.datasource.username=root
#数据库密码
spring.datasource.password=root
#数据源类型(阿里巴巴)
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#thymeleaf
spring.thymeleaf.cache=false
#日期格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#mybatis-plus
#mybatis-plus.mapper-locations=classpath:mapper/*Mapper.xml,classpath:mapper/*/*Mapper.xml
#日志
logging.level.com.bdqn=debug

添加静态资源

加入静态资源

1.将素材解压后放到项目的static目录下,如下图所示

image-20191210132538450

2.运行测试是否能够正确访问首页及登录页面

复制登录页面

将resources/page/login目录下的login.html页面复制到resources文件夹下,如图所示

image-20191210134217632

修改login.html当前页面的样式及脚本路径,并将login.js复制到login.html页面,代码如下:

<!DOCTYPE html>
<html class="loginHtml">
<head>
	<meta charset="utf-8">
	<title>登录--layui后台管理模板 2.0</title>
	<meta name="renderer" content="webkit">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
	<meta name="apple-mobile-web-app-status-bar-style" content="black">
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="format-detection" content="telephone=no">
	<link rel="icon" href="/resources/favicon.ico">
	<link rel="stylesheet" href="/resources/layui/css/layui.css" media="all" />
	<link rel="stylesheet" href="/resources/css/public.css" media="all" />
</head>
<body class="loginBody">
	<form class="layui-form">
		<div class="login_face"><img src="/resources/images/face.jpg" class="userAvatar"></div>
		<div class="layui-form-item input-item">
			<label for="userName">用户名</label>
			<input type="text" placeholder="请输入用户名" autocomplete="off" id="userName" class="layui-input" lay-verify="required">
		</div>
		<div class="layui-form-item input-item">
			<label for="password">密码</label>
			<input type="password" placeholder="请输入密码" autocomplete="off" id="password" class="layui-input" lay-verify="required">
		</div>
		<div class="layui-form-item input-item" id="imgCode">
			<label for="code">验证码</label>
			<input type="text" placeholder="请输入验证码" autocomplete="off" id="code" class="layui-input">
			<img src="/resources/images/code.jpg">
		</div>
		<div class="layui-form-item">
			<button class="layui-btn layui-block" lay-filter="login" lay-submit>登录</button>
		</div>
		<div class="layui-form-item layui-row">
			<a href="javascript:;" class="seraph icon-qq layui-col-xs4 layui-col-sm4 layui-col-md4 layui-col-lg4"></a>
			<a href="javascript:;" class="seraph icon-wechat layui-col-xs4 layui-col-sm4 layui-col-md4 layui-col-lg4"></a>
			<a href="javascript:;" class="seraph icon-sina layui-col-xs4 layui-col-sm4 layui-col-md4 layui-col-lg4"></a>
		</div>
	</form>
	<script type="text/javascript" src="/resources/layui/layui.js"></script>
	<script type="text/javascript" src="login.js"></script>
	<script type="text/javascript" src="/resources/js/cache.js"></script>
	<script>
		layui.use(['form','layer','jquery'],function(){
			var form = layui.form,
					layer = parent.layer === undefined ? layui.layer : top.layer
			$ = layui.jquery;
			

			//登录按钮
			form.on("submit(login)",function(data){
				$(this).text("登录中...").attr("disabled","disabled").addClass("layui-disabled");
				setTimeout(function(){
					window.location.href = "/layuicms2.0";
				},1000);
				return false;
			})

			//表单输入效果
			$(".loginBody .input-item").click(function(e){
				e.stopPropagation();
				$(this).addClass("layui-input-focus").find(".layui-input").focus();
			})
			$(".loginBody .layui-form-item .layui-input").focus(function(){
				$(this).parent().addClass("layui-input-focus");
			})
			$(".loginBody .layui-form-item .layui-input").blur(function(){
				$(this).parent().removeClass("layui-input-focus");
				if($(this).val() != ''){
					$(this).parent().addClass("layui-input-active");
				}else{
					$(this).parent().removeClass("layui-input-active");
				}
			})
		})

	</script>
</body>
</html>

删除登录页面的公告弹出层

删除resources/js目录下的cache.js文件中的showNotice()方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3YM6ARa-1620146254230)(images/image-20191210134859280.png)]

修改主页面index.html

删除顶部菜单

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PluR0nEB-1620146254231)(images/image-20191210140139994.png)]

修改左侧导航栏

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndpUtDYs-1620146254232)(images/image-20191210142717701.png)]

修改layui版本

修改layui.js及layui.css这两个文件

layui.css

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DTvkhOY3-1620146254233)(images/image-20191210143823449.png)]

layui.js

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6S56MHrM-1620146254234)(images/image-20191210143938104.png)]

代码生成器

package com.bdqn;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.apache.commons.lang3.StringUtils;

import java.util.Scanner;

public class CodeGenerator {

    private static String author ="KazuGin";//作者名称
    private static String outputDir ="E:\\";//生成的位置
    private static String driver ="com.mysql.cj.jdbc.Driver";//驱动,注意版本
    //连接路径,注意修改数据库名称
    private static String url ="jdbc:mysql://localhost:3306/db_erp?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
    private static String username ="root";//数据库用户名
    private static String password ="root";//数据库密码
    private static String tablePrefix ="t_";//数据库表的前缀,如t_user
    private static String parentPackage = "com.bdqn";//顶级包结构
    private static String dao = "dao";//数据访问层包名称
    private static String service = "service";//业务逻辑层包名称
    private static String entity = "entity";//实体层包名称
    private static String controller = "controller";//控制器层包名称
    private static String mapperxml = "mapper";//mapper映射文件包名称
    private static String moduleName = "sys";//模块名

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {

        //1. 全局配置
        GlobalConfig config = new GlobalConfig();
        config.setAuthor(author) // 作者
                .setOutputDir(outputDir) // 生成路径
                .setFileOverride(true)  // 文件覆盖
                .setIdType(IdType.AUTO) // 主键策略
                .setServiceName("%sService")  // 设置生成的service接口的名字的首字母是否为I,加%s则不生成I
                .setBaseResultMap(true)	//映射文件中是否生成ResultMap配置
                .setBaseColumnList(true);	//生成通用sql字段

        //2. 数据源配置
        DataSourceConfig dsConfig  = new DataSourceConfig();
        dsConfig.setDbType(DbType.MYSQL)  // 设置数据库类型
                .setDriverName(driver)	//设置驱动
                .setUrl(url)			//设置连接路径
                .setUsername(username)	//设置用户名
                .setPassword(password);	//设置密码
        //4. 包名策略配置
        PackageConfig pkConfig = new PackageConfig();
        pkConfig.setParent(parentPackage)//顶级包结构
                .setMapper(dao)	//数据访问层
                .setService(service)	//业务逻辑层
                .setController(controller)	//控制器
                .setEntity(entity)	//实体类
                .setXml(mapperxml)//mapper映射文件
                .setModuleName(scanner("模块名"));//模块名;

        //3. 策略配置
        StrategyConfig stConfig = new StrategyConfig();
        stConfig.setCapitalMode(true) //全局大写命名
                .setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略
                .setColumnNaming(NamingStrategy.underline_to_camel)
                //.setTablePrefix(tablePrefix) //表前缀
                .setInclude(scanner("请输入表名(多个以英文逗号隔开):").split(","))
                .setTablePrefix(pkConfig.getModuleName()+"_")
                //.setInclude(tables) // 生成的表
                .setControllerMappingHyphenStyle(true);





        //5. 整合配置
        AutoGenerator ag = new AutoGenerator();
        ag.setGlobalConfig(config)
                .setDataSource(dsConfig)
                .setStrategy(stConfig)
                .setPackageInfo(pkConfig);
        //6. 执行
        ag.execute();

    }

}

用户登录

login.html

在templates目录下创建login.html页面,复制之前修改好的login.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EtIgcnXF-1620146254234)(images/image-20191210171018482.png)]

MyWebMvcConfiguration

在com.bdqn.sys.config包下添加MyWebMvcConfiguration类,配置默认访问页面及静态资源的加载

package com.bdqn.sys.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 自定义webmvc配置
 */
@Configuration
public class MyWebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //去到登录页面请求
        registry.addViewController("/sys/login").setViewName("login");
        registry.addViewController("/").setViewName("login");
        registry.addViewController("/login.html").setViewName("login");
    }


    /**
     * 加载静态资源
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }

生成User相关的类

生成以下Java类:

  1. User实体类
  2. UserMapper接口
  3. UserMapper.xml映射文件
  4. UserService接口
  5. UserServiceImpl实现类
  6. UserController控制器

User类

注意:将属性的LocalDateTime数据类型改成java.util.Date日期类型

UserService

package com.bdqn.sys.service;

import com.bdqn.sys.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author KazuGin
 * @since 2019-12-10
 */
public interface UserService extends IService<User> {

    /**
     * 根据用户名查询用户信息
     * @param userName
     * @return
     * @throws Exception
     */
    User findUserByUserName(String userName) throws Exception;
}

UserServiceImpl

package com.bdqn.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bdqn.sys.entity.User;
import com.bdqn.sys.dao.UserMapper;
import com.bdqn.sys.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author KazuGin
 * @since 2019-12-10
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    public User findUserByUserName(String userName) throws Exception {
        //创建条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        //根据登录名称查询
        queryWrapper.eq("loginname",userName);
        return userMapper.selectOne(queryWrapper);
    }
}

LoginUserVo

创建登录用户对象

package com.bdqn.sys.vo;

import com.bdqn.sys.entity.User;

import java.util.Set;

/**
 * 登录用户类
 */
public class LoginUserVo {
    private User user;//用户信息
    private Set<String> roles;//角色列表
    private Set<String> permissions;//权限列表

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Set<String> getRoles() {
        return roles;
    }

    public void setRoles(Set<String> roles) {
        this.roles = roles;
    }

    public Set<String> getPermissions() {
        return permissions;
    }

    public void setPermissions(Set<String> permissions) {
        this.permissions = permissions;
    }

    public LoginUserVo() {
    }

    /**
     * 登录用户
     * @param user          当前登录用户信息
     * @param roles         当前用户拥有的角色列表
     * @param permissions   当前用户拥有的角色列表
     */
    public LoginUserVo(User user, Set<String> roles, Set<String> permissions) {
        this.user = user;
        this.roles = roles;
        this.permissions = permissions;
    }
}

UserRealm

package com.bdqn.sys.realm;

import com.bdqn.sys.entity.User;
import com.bdqn.sys.service.UserService;
import com.bdqn.sys.vo.LoginUserVo;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;


public class UserRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    /**
     * UserRealm的域名
     * @return
     */
    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取当前登录主体
        String userName = (String) authenticationToken.getPrincipal();
        try {
            //根据用户名查询用户信息的方法
            User user = userService.findUserByUserName(userName);
            //对象不为空
            if(user!=null){
                //创建当前登录用户对象
                //创建登录用户对象,传入用户信息,角色列表,权限列表
                LoginUserVo loginUserVo = new LoginUserVo(user,null,null);
                //创建盐值(以用户名作为盐值)
                ByteSource salt = ByteSource.Util.bytes(user.getSalt());
                //创建身份验证对象
                //参数1:当前登录对象  参数2:密码  参数3:盐值 参数4:域名
                SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(loginUserVo,user.getLoginpwd(),salt,getName());
                return info;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //验证失败
        return null;
    }
}

ShiroConfiguration

package com.bdqn.sys.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.bdqn.sys.realm.UserRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfiguration {
    private static final String SHIRO_DIALECT = "shiroDialect";
    private static final String SHIRO_FILTER = "shiroFilter";
    private String hashAlgorithmName = "md5";// 加密方式
    private int hashIterations = 2;// 散列次数


    /**
     * 声明凭证匹配器
     */
    @Bean("credentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName(hashAlgorithmName);
        credentialsMatcher.setHashIterations(hashIterations);
        return credentialsMatcher;
    }

    /**
     * 注入自定义的UserRealm
     * @return
     */
    @Bean
    public UserRealm getUserRealm(CredentialsMatcher credentialsMatcher){
        UserRealm userRealm = new UserRealm();
        //注入凭证匹配器
        userRealm.setCredentialsMatcher(credentialsMatcher);
        return userRealm;
    }


    /**
     * 创建DefaultWebSecurityManager对象,关联自定义的UserRealm对象
     * @param userRealm
     * @return
     */
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm){
        //创建DefaultWebSecurityManager对象
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //关联自定义realm
        defaultWebSecurityManager.setRealm(userRealm);
        //返回DefaultWebSecurityManager对象
        return defaultWebSecurityManager;
    }

    /**
     * 创建ShiroFilterFactoryBean对象,设置安全管理器
     * @param securityManager
     * @return
     */
    @Bean(SHIRO_FILTER)
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        //创建ShiroFilterFactoryBean对象
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        factoryBean.setSecurityManager(securityManager);
        //设置过滤器链
        Map<String,String> filterChainDefinitionsMap = new LinkedHashMap<String,String>();
        //放行路径(匿名访问)
        filterChainDefinitionsMap.put("/resources/**","anon");//静态资源
        filterChainDefinitionsMap.put("/sys/user/login","anon");//登录请求
        filterChainDefinitionsMap.put("/sys/login","anon");//去到登录页面
        filterChainDefinitionsMap.put("/","anon");//去到登录页面
        filterChainDefinitionsMap.put("/favicon.ico","anon");//去到登录页面
        //退出
        filterChainDefinitionsMap.put("/logout","logout");
        //拦截请求
        filterChainDefinitionsMap.put("/**","authc");
        //将过滤器链设置到shiroFilterFactoryBean对象中
        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionsMap);
        //身份验证失败要去到登录页面
        //如果不设置loginUrl,则默认找login.jsp页面
        factoryBean.setLoginUrl("/sys/login");
        return factoryBean;
    }

    /**
     * 注册shiro的委托过滤器,相当于之前在web.xml里面配置的
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxy() {
        FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean = new FilterRegistrationBean<DelegatingFilterProxy>();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName(SHIRO_FILTER);
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }
    /* 加入注解的使用,不加入这个注解不生效--开始 */
    /**
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    /* 加入注解的使用,不加入这个注解不生效--结束 */

    /**
     * 这里是为了能在html页面引用shiro标签,上面两个函数必须添加,不然会报错
     *
     * @return
     */
    @Bean(name = SHIRO_DIALECT)
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

JSONResult

创建返回值类型结果对象

package com.bdqn.sys.utils;

/**
 * 返回值JSON结果
 */
public class JSONResult {

    //是否成功
    private Boolean success;
    //提示信息
    private String message;

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public JSONResult(){

    }

    /**
     * 带参构造函数
     * @param success   是否成功
     * @param message   提示信息
     */
    public JSONResult(Boolean success, String message) {
        this.success = success;
        this.message = message;
    }
}

SystemConstant

创建系统常量接口

package com.bdqn.sys.utils;

public interface SystemConstant {


    /**
     * 当前登录用户的key
     */
    String LOGINUSER = "loginUser";

    /**
     * 成功
     */
    Boolean OK = true;

    /**
     * 失败
     */
    Boolean ERROR = false;


    /**
     * 登录成功
     */
    JSONResult LOGIN_SUCCESS = new JSONResult(SystemConstant.OK,"登录成功");
    /**
     * 登录失败,用户名或密码错误
     */
    JSONResult LOGIN_ERROR_PASS = new JSONResult(SystemConstant.ERROR,"登录失败,用户名或密码错误");
}

UserController

package com.bdqn.sys.controller;


import com.bdqn.sys.utils.JSONResult;
import com.bdqn.sys.utils.SystemConstant;
import com.bdqn.sys.vo.LoginUserVo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author KazuGin
 * @since 2019-12-10
 */
@RestController
@RequestMapping("/sys/user")
public class UserController {


    /**
     * 登录
     * @param loginname     用户名
     * @param pwd           密码
     * @param session
     * @return
     */
    @PostMapping("/login")
    public JSONResult login(String loginname, String pwd, HttpSession session){
        try {
            //获取当前登录主体对象
            Subject subject = SecurityUtils.getSubject();
            //创建令牌对象
            UsernamePasswordToken token = new UsernamePasswordToken(loginname,pwd);
            //登录
            subject.login(token);
            //获取当前登录对象
            LoginUserVo userVo =(LoginUserVo) subject.getPrincipal();
            //保存session
            session.setAttribute(SystemConstant.LOGINUSER,userVo.getUser());
            //登录成功
            return SystemConstant.LOGIN_SUCCESS;
        } catch (AuthenticationException e) {
            e.printStackTrace();
            //登录失败,用户名或密码错误
            return SystemConstant.LOGIN_ERROR_PASS;
        }
    }

}

SystemController

该控制器的作用是跳转页面路径

package com.bdqn.sys.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/sys")
public class SystemController {

    /**
     * 去到后台首页
     * @return
     */
    @RequestMapping("/index")
    public String toIndex(){
        return "system/home/index";
    }
}

index.html

在templates/system/home目录下新建index.html页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYnHhEE1-1620146254235)(images/image-20191210173319924.png)]

首页桌面工作台

创建desktopManager.html

在templates/system/home目录下添加desktopManager.html页面(具体页面参考提供素材)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GgxpOTET-1620146254236)(images/image-20191210174221339.png)]

修改SystemController

    /**
     * 跳转到桌面工作台
     * @return
     */
    @RequestMapping("/desktop")
    public String desktop() {
        return "system/home/desktopManager";
    }

首页左侧菜单导航树

生成Permission相关的类

生成以下Java类:

  1. Permission实体类
  2. PermissionMapper接口
  3. PermissionMapper.xml映射文件
  4. PermissionService接口
  5. PermissionServiceImpl实现类
  6. PermissionController控制器

创建DataGridViewResult类

layui的数据表格组件需要返回4个属性值,分别是code,msg,count,data。故封装DataGridViewResult类,代码如下:

package com.bdqn.sys.utils;

/**
 * layui 数据表格类
 */
public class DataGridViewResult {
    private Integer code=0;//执行状态码
    private String msg="";//提示信息
    private Long count=0L;//数量
    private Object data;//数据

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Long getCount() {
        return count;
    }

    public void setCount(Long count) {
        this.count = count;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public DataGridViewResult(Long count, Object data) {
        super();
        this.count = count;
        this.data = data;
    }
    public DataGridViewResult(Object data) {
        super();
        this.data = data;
    }

    public DataGridViewResult() {
    }
}

创建PermissionVo

在com.bdqn.sys.vo包下创建PermissionVo类,添加layui的分页组件属性

package com.bdqn.sys.vo;

import com.bdqn.sys.entity.Permission;

/**
 * 权限扩展类
 */
public class PermissionVo extends Permission {
    private Integer page;//当前页码
    private Integer limit;//每页显示数量

    public Integer getPage() {
        return page;
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public Integer getLimit() {
        return limit;
    }

    public void setLimit(Integer limit) {
        this.limit = limit;
    }
}

修改SystemConstant接口

    /**
     * 类型为菜单:用于首页左侧导航栏
     */
    String TYPE_MENU = "menu";

    /**
     * 类型为权限
     */
    String TYPE_PERMISSION ="permission" ;

    /**
     * 菜单是否展开,1展开
     */
    Integer OPEN_TRUE = 1;

    /**
     * 菜单是否展开,0不展开
     */
    Integer OPEN_FALSE = 0;

    /**
     * 角色为超级管理员
     */
    Integer SUPERUSER = 0;

创建TreeNode

layui的tree组件数据源参数如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DoZ8CKjo-1620146254236)(images/image-20191211100126350.png)]

将tree组件的数据源属性封装JavaBean

package com.bdqn.sys.utils;

import java.util.ArrayList;
import java.util.List;

/**
 * 树节点属性类
 */
public class TreeNode {

    private Integer id;//菜单节点编号
    private Integer pid;//父节点菜单编号
    private String title;//菜单节点名称
    private String icon;//菜单节点图标
    private String href;//菜单路径
    private Boolean spread;//是否展开
    //子节点菜单
    private List<TreeNode> children = new ArrayList<TreeNode>();

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getPid() {
        return pid;
    }

    public void setPid(Integer pid) {
        this.pid = pid;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public String getHref() {
        return href;
    }

    public void setHref(String href) {
        this.href = href;
    }

    public Boolean getSpread() {
        return spread;
    }

    public void setSpread(Boolean spread) {
        this.spread = spread;
    }

    public List<TreeNode> getChildren() {
        return children;
    }

    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

    public TreeNode() {
    }

    /**
     * 构建树节点菜单
     * @param id    节点编号
     * @param pid   父节点
     * @param title 节点标题
     * @param icon  节点图标
     * @param href  节点菜单路径
     * @param spread    节点展开状态
     */
    public TreeNode(Integer id, Integer pid, String title, String icon, String href, Boolean spread) {
        this.id = id;
        this.pid = pid;
        this.title = title;
        this.icon = icon;
        this.href = href;
        this.spread = spread;
    }

}

创建TreeNodeBuilder

package com.bdqn.sys.utils;

import java.util.ArrayList;
import java.util.List;

/**
 * 创建节点层级关系
 */
public class TreeNodeBuilder {


    /**
     * 创建节点层级关系
     * @param treeNodes     节点对象集合
     * @param topPid        父节点
     * @return
     */
    public static List<TreeNode> build(List<TreeNode> treeNodes,Integer topPid){
        List<TreeNode> nodes=new ArrayList<TreeNode>();
        //循环遍历节点集合
        for (TreeNode n1 : treeNodes) {
            //如果当前节点为根节点,则将当前节点添加到节点数组中
            if(n1.getPid()==topPid) {
                nodes.add(n1);
            }
            //如果当前子节点对应的节点相等,则添加到子节点集合中
            for (TreeNode n2 : treeNodes) {
                if(n1.getId()==n2.getPid()) {
                    n1.getChildren().add(n2);
                }
            }
        }

        return nodes;
    }

}

创建MenuController

package com.bdqn.sys.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bdqn.sys.entity.Permission;
import com.bdqn.sys.entity.User;
import com.bdqn.sys.service.PermissionService;
import com.bdqn.sys.utils.DataGridViewResult;
import com.bdqn.sys.utils.SystemConstant;
import com.bdqn.sys.utils.TreeNode;
import com.bdqn.sys.utils.TreeNodeBuilder;
import com.bdqn.sys.vo.PermissionVo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/sys/menu")
public class MenuController {

    @Resource
    private PermissionService permissionService;


    @RequestMapping("/loadIndexLeftMenu")
    public DataGridViewResult loadIndexLeftMenu(PermissionVo permissionVo, HttpSession session){
        List<Permission> permissions = new ArrayList<Permission>();
        try {
            QueryWrapper<Permission> queryWrapper = new QueryWrapper<Permission>();
            queryWrapper.eq("type", SystemConstant.TYPE_MENU);//只查询菜单
            //获取当前登录用户
            User user = (User) session.getAttribute(SystemConstant.LOGINUSER);
            //如果当前登录用户为超级管理员,则能查看所有菜单
            if(user.getType()==SystemConstant.SUPERUSER){
                //查询菜单列表
                permissions = permissionService.list(queryWrapper);
            }else{//普通用户:需要根据当前用户的角色及权限加载菜单列表
                //查询菜单列表
                permissions = permissionService.list(queryWrapper);
            }
            //构建菜单节点集合
            List<TreeNode> treeNodes = new ArrayList<TreeNode>();
            for (Permission permission : permissions) {
                //判断当前节点是否展开,是则为true,否则为false
                Boolean spread = SystemConstant.OPEN_TRUE == permission.getOpen() ? true : false;
                treeNodes.add(new TreeNode(permission.getId(), permission.getPid(),
                        permission.getTitle(), permission.getIcon(), 
                        permission.getHref(), spread));
            }
            //构建节点菜单层级关系(参数1:节点集合数据源,参数2:根节点编号)
            List<TreeNode> treeNodeList = TreeNodeBuilder.build(treeNodes,1);
            //将节点返回出去
            return new DataGridViewResult(treeNodeList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

修改index.js

修改resources/js下的index.js文件,代码如图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gDGiJI35-1620146254237)(images/image-20191211101410065.png)]

日志管理

添加日志

生成Log相关的类

生成以下Java类:

  1. Log实体类
  2. LogMapper接口
  3. LogMapper.xml映射文件
  4. LogService接口
  5. LogServiceImpl实现类
  6. LogController控制器

修改Log类

  1. 将属性的LocalDateTime数据类型改成java.util.Date日期类型
  2. 生成无参带参构造方法
	//无参构造方法
	public Log() {
    }

    /**
     * 添加日志时使用
     * @param content       日志内容
     * @param type          操作类型
     * @param loginname     操作人
     * @param userid        操作人id
     * @param loginip       登录ip
     * @param createtime    创建时间
     */
    public Log(String content, String type, String loginname, Integer userid, String loginip, Date createtime) {
        this.content = content;
        this.type = type;
        this.loginname = loginname;
        this.userid = userid;
        this.loginip = loginip;
        this.createtime = createtime;
    }

记录登录日志信息

修改UserController控制器代码,记录登录方法的日志

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OZPr0mkv-1620146254237)(images/image-20191211153226216.png)]

查询日志

修改SystemController

    /**
     * 日志管理页面
     * @return
     */
    @RequestMapping("/toLogManager")
    public String toLogManager() {
        return "system/log/logManager";
    }

创建logManager.html

在templates/resources/system下创建logManager.html(请参考提供的素材)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ie1VgcbG-1620146254237)(images/image-20191211170438720.png)]

创建LogVo

package com.bdqn.sys.vo;

import com.bdqn.sys.entity.Log;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
 * 日志扩展类
 */
public class LogVo extends Log {
    private Integer page;//当前页码
    private Integer limit;//每页显示数量

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date startTime;//开始时间
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date endTime;//结束时间

    public Integer getPage() {
        return page;
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public Integer getLimit() {
        return limit;
    }

    public void setLimit(Integer limit) {
        this.limit = limit;
    }

    public Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }
}

修改LogController

package com.bdqn.sys.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bdqn.sys.entity.Log;
import com.bdqn.sys.service.LogService;
import com.bdqn.sys.utils.DataGridViewResult;
import com.bdqn.sys.utils.JSONResult;
import com.bdqn.sys.utils.SystemConstant;
import com.bdqn.sys.vo.LogVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Arrays;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author KazuGin
 * @since 2019-12-11
 */
@RestController
@RequestMapping("/sys/log")
public class LogController {


    @Resource
    private LogService logService;

    @RequestMapping("/loglist")
    public DataGridViewResult findLogList(LogVo logVo){
        //创建分页对象,并指定当前页码及每页显示数量
        IPage<Log> page = new Page<Log>(logVo.getPage(),logVo.getLimit());
        //设置查询条件
        QueryWrapper<Log> queryWrapper = new QueryWrapper<Log>();
        //登录名模糊查询
        queryWrapper.like(StringUtils.isNotBlank(logVo.getLoginname()),"loginname",logVo.getLoginname());
        //操作类型
        queryWrapper.eq(StringUtils.isNotBlank(logVo.getType()),"type",logVo.getType());
        //开始时间
        queryWrapper.ge(logVo.getStartTime()!=null,"createtime",logVo.getStartTime());
        //结束时间
        queryWrapper.le(logVo.getEndTime()!=null,"createtime",logVo.getEndTime());
        //设置排序
        queryWrapper.orderByDesc("createtime");//登录时间降序
        //调用分页查询方法
        logService.page(page,queryWrapper);
        //返回数据
        return new DataGridViewResult(page.getTotal(),page.getRecords());
    }
}

MyBatisPlusConfig

在com.bdqn.sys.config包下创建mybatis-plus分页插件配置类

package com.bdqn.sys.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration//标记该类是一个配置类
@EnableTransactionManagement//开启事务管理
@MapperScan(basePackages = {"com.bdqn.sys.dao"})//加载mapper接口所在的包
public class MyBatisPlusConfig {


    /**
     * 注入分页插件
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }

}

删除日志

修改logManager.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N90pQDXg-1620146254238)(images/image-20191211171119099.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rot8v3w7-1620146254238)(images/image-20191211171132973.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjJleyHW-1620146254239)(images/image-20191211171222450.png)]

修改SystemConstant

    /**
     * 删除成功
     */
    JSONResult DELETE_SUCCESS = new JSONResult(SystemConstant.OK,"删除成功");
    /**
     * 删除失败
     */
    JSONResult DELETE_ERROR = new JSONResult(SystemConstant.ERROR,"删除失败");
    /**
     * 添加成功
     */
    JSONResult ADD_SUCCESS = new JSONResult(SystemConstant.OK,"添加成功");
    /**
     * 添加失败
     */
    JSONResult ADD_ERROR = new JSONResult(SystemConstant.ERROR,"添加失败");
    /**
     * 修改成功
     */
    JSONResult UPDATE_SUCCESS = new JSONResult(SystemConstant.OK,"修改成功");
    /**
     * 修改失败
     */
    JSONResult UPDATE_ERROR = new JSONResult(SystemConstant.ERROR,"修改失败");

LogController

@RequestMapping("/batchDelete")
public JSONResult batchDelete(String ids){
    try {
        String [] idsStr = ids.split(",");
        //删除
        if(logService.removeByIds(Arrays.asList(idsStr))){
            //删除成功
            return SystemConstant.DELETE_SUCCESS;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    //删除失败
    return SystemConstant.DELETE_ERROR;
}

公告管理

公告查询

生成Notice相关的类

生成以下Java类:

  1. Notice实体类
  2. NoticeMapper接口
  3. NoticeMapper.xml映射文件
  4. NoticeService接口
  5. NoticeServiceImpl实现类
  6. NoticeController控制器

修改SystemController

    /**
     * 去到公告管理页面
     * @return
     */
    @RequestMapping("/toNoticeManager")
    public String toNoticeManager() {
        return "system/notice/noticeManager";
    }

创建noticeManager.html

在templates/system/notice下创建noticeManager.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GFQBQjhR-1620146254239)(images/image-20191212154900214.png)]

创建NoticeVo类

package com.bdqn.sys.vo;

import com.bdqn.sys.entity.Notice;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
 * 公告扩展类
 */
public class NoticeVo extends Notice {
    private Integer page;//当前页码
    private Integer limit;//每页显示数量

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date startTime;//开始时间
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date endTime;//结束时间

    public Integer getPage() {
        return page;
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public Integer getLimit() {
        return limit;
    }

    public void setLimit(Integer limit) {
        this.limit = limit;
    }

    public Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }
}

NoticeController

package com.bdqn.sys.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bdqn.sys.entity.Notice;
import com.bdqn.sys.entity.User;
import com.bdqn.sys.service.NoticeService;
import com.bdqn.sys.utils.DataGridViewResult;
import com.bdqn.sys.utils.JSONResult;
import com.bdqn.sys.utils.SystemConstant;
import com.bdqn.sys.vo.NoticeVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author KazuGin
 * @since 2019-12-11
 */
@RestController
@RequestMapping("/sys/notice")
public class NoticeController {
    @Resource
    private NoticeService noticeService;


    @ResponseBody
    @RequestMapping("/noticeList")
    public DataGridViewResult findNoticeList(NoticeVo noticeVo){
        //创建分页对象
        IPage<Notice> page = new Page<Notice>(noticeVo.getPage(),noticeVo.getLimit());
        //创建条件构造器
        QueryWrapper<Notice> queryWrapper = new QueryWrapper<Notice>();
        //标题查询
        queryWrapper.like(StringUtils.isNotBlank(noticeVo.getTitle()),"title",noticeVo.getTitle());
        //发布人
        queryWrapper.like(StringUtils.isNotBlank(noticeVo.getOpername()),"opername",noticeVo.getOpername());
        //开始时间
        queryWrapper.ge(noticeVo.getStartTime()!=null,"createtime",noticeVo.getStartTime());
        //结束时间
        queryWrapper.le(noticeVo.getEndTime()!=null,"createtime",noticeVo.getEndTime());
        //排序
        queryWrapper.orderByDesc("createtime");
        //分页查询
        noticeService.page(page,queryWrapper);
        //返回数据
        return new DataGridViewResult(page.getTotal(),page.getRecords());
    }
}

添加公告

修改noticeManager.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T4tvRYsj-1620146254239)(images/image-20191212164944231.png)]

NoticeController

    /**
     * 发布公告
     * @param notice
     * @param request
     * @return
     */
    @RequestMapping("/addNotice")
    public JSONResult addNotice(Notice notice, HttpServletRequest request){
        User user = (User) request.getSession().getAttribute(SystemConstant.LOGINUSER);
        notice.setOpername(user.getName());
        notice.setCreatetime(new Date());
        //保存公告
        if(noticeService.save(notice)){
            return SystemConstant.ADD_SUCCESS;
        }
        return SystemConstant.ADD_ERROR;
    }

修改公告

修改noticeManager.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V66SNpTW-1620146254240)(images/image-20191212172542413.png)]

NoticeController

    /**
     * 修改公告
     * @param notice
     * @return
     */
    @RequestMapping("/updateNotice")
    public JSONResult updateNotice(Notice notice){
        //保存公告
        if(noticeService.updateById(notice)){
            return SystemConstant.UPDATE_SUCCESS;
        }
        return SystemConstant.UPDATE_ERROR;
    }

删除公告

noticeManager.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x5Yjgamc-1620146254240)(images/image-20191212172720808.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N9QIojqR-1620146254241)(images/image-20191212172745512.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YjBhYhU5-1620146254241)(images/image-20191212172806042.png)]

NoticeController

    /**
     * 删除公告
     * @param id
     * @return
     */
    @RequestMapping("/deleteById")
    public JSONResult deleteById(int id){
        if(noticeService.removeById(id)){
            return SystemConstant.DELETE_SUCCESS;
        }
        return SystemConstant.DELETE_ERROR;
    }

批量删除公告

noticeManager.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gMDB7Sto-1620146254242)(images/image-20191212172952525.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8oE0NB1K-1620146254242)(images/image-20191212173013061.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vqcrOeqO-1620146254243)(images/image-20191212173113420.png)]

NoticeController

    @RequestMapping("/batchDelete")
    public JSONResult batchDelete(String ids){
        try {
            String [] idsStr = ids.split(",");
            //删除
            if(noticeService.removeByIds(Arrays.asList(idsStr))){
                //删除成功
                return SystemConstant.DELETE_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //删除失败
        return SystemConstant.DELETE_ERROR;
    }

查看公告信息

noticeManager.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y8vZ5r3k-1620146254244)(images/image-20191212173250246.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pywDCzbB-1620146254244)(images/image-20191212173317658.png)]

部门管理

查询部门

生成Dept相关的类

生成以下Java类:

  1. Dept实体类
  2. DeptMapper接口
  3. DeptMapper.xml映射文件
  4. DeptService接口
  5. DeptServiceImpl实现类
  6. DeptController控制器

创建dept相关页面

在templates/system/dept目录下创建3个页面,分别是left.html,right.html,deptManager.html页面

添加dtree树组件素材

将dtree树组件相关的素材放到static/resources目录下,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-usqleAKX-1620146254244)(images/image-20191213121039066.png)]

创建left.html页面

具体页面代码参考提供素材

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjRhkEYb-1620146254245)(images/image-20191213143611222.png)]

创建deptManager.html页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>部门管理</title>
</head>
<frameset cols="200,*" border="1"  frameborder="yes">
    <frame src="/sys/toDeptLeft" name="left">
    <frame src="/sys/toDeptRight" name="right">
</frameset>
</html>
创建right.html页面

具体页面代码参考提供素材

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3dm2l8Sc-1620146254245)(images/image-20191213162003846.png)]

DeptController

@RestController
@RequestMapping("/sys/dept")
public class DeptController {

    @Resource
    private DeptService deptService;

    //加载left.html左侧菜单树
    @RequestMapping("/loadDeptTreeLeft")
    public DataGridViewResult loadDeptTreeLeft(){
        //查询所有部门
        List<Dept> deptList = deptService.list();
        //创建节点集合
        List<TreeNode> treeNodes = new ArrayList<TreeNode>();
        //循环遍历部门集合
        for (Dept dept : deptList) {
            //是否展开
            Boolean spread = dept.getOpen()==1?true:false;
            treeNodes.add(new TreeNode(dept.getId(),dept.getPid(),dept.getTitle(),spread));
        }
        return new DataGridViewResult(treeNodes);
    }

    //加载右边数据表格数据
    @RequestMapping("/deptList")
    public DataGridViewResult findDeptList(DeptVo deptVo){
        //创建分页对象
        IPage<Dept> page = new Page<Dept>(deptVo.getPage(),deptVo.getLimit());
        //创建条件构造器
        QueryWrapper<Dept> queryWrapper = new QueryWrapper<Dept>();
        //部门名称查询
        queryWrapper.like(StringUtils.isNotBlank(deptVo.getTitle()),"title",deptVo.getTitle());
        //地址
        queryWrapper.like(StringUtils.isNotBlank(deptVo.getAddress()),"address",deptVo.getAddress());
        //编号
        queryWrapper.eq(deptVo.getId()!=null,"id",deptVo.getId()).or().eq(deptVo.getId()!=null,"pid",deptVo.getId());
        //排序
        queryWrapper.orderByAsc("id");
        //分页查询
        deptService.page(page,queryWrapper);
        //返回数据
        return new DataGridViewResult(page.getTotal(),page.getRecords());
    }
}

修改TreeNode类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-esyFelN7-1620146254246)(images/image-20191213170052245.png)]

    /**
     * 构建树节点菜单
     * @param id        节点编号
     * @param pid       父节点编号
     * @param title     节点名称
     * @param spread    节点是否展开
     */
    public TreeNode(Integer id, Integer pid, String title, Boolean spread) {
        this.id = id;
        this.pid = pid;
        this.title = title;
        this.spread = spread;
    }

添加部门

修改right.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w37nrqCm-1620146254246)(images/image-20191213165203227.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rDdhmbFg-1620146254247)(images/image-20191213165509551.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZzL0SxMX-1620146254247)(images/image-20191213165224715.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hecdn9i4-1620146254247)(images/image-20191213165255066.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ycv0shqY-1620146254248)(images/image-20191213165328270.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ilDHQGsP-1620146254248)(images/image-20191213165556356.png)]

DeptController

    @PostMapping("/addDept")
    public JSONResult addDept(Dept dept){
        try {
            //设置添加时间
            dept.setCreatetime(new Date());
            //调用新增的方法
            if(deptService.save(dept)){
                //新增成功
                return SystemConstant.ADD_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SystemConstant.ADD_ERROR;
    }

修改部门

修改right.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aEzUsGiU-1620146254249)(images/image-20191213165855859.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KZSykGaW-1620146254250)(images/image-20191213170007460.png)]

DeptController

@PostMapping("/updateDept")
public JSONResult updateDept(Dept dept){
    try {
        //调用修改的方法
        if(deptService.updateById(dept)){
            //修改成功
            return SystemConstant.UPDATE_SUCCESS;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return SystemConstant.UPDATE_ERROR;
}

删除部门

需求

点击删除部门按钮时,判断当前要删除的部门是否有子部门信息,如果有子节点,则提示不能删除,否则直接删除

修改right.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cGAehRpG-1620146254251)(images/image-20191213170634816.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M0jvtcah-1620146254251)(images/image-20191213170613747.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IMG6joMm-1620146254252)(images/image-20191213170712512.png)]

DeptController

    /**
     * 判断当前节点是否有子节点
     * @param id
     * @return
     */
    @RequestMapping("/checkDeptHasChildren")
    public String checkDeptHasChildren(int id){
        Map<String,Object> map = new LinkedHashMap<String,Object>();
        //构建条件对象
        QueryWrapper<Dept> queryWrapper = new QueryWrapper<Dept>();
        queryWrapper.eq("pid",id);//查询父节点下是否有数据
        //查询
        List<Dept> deptList = deptService.list(queryWrapper);
        //判断集合是否有数据,有则不能删除
        if(deptList.size()>0){
            map.put(SystemConstant.EXIST,true);//存在
        }else{
            map.put(SystemConstant.EXIST,false);//不存在
        }
        return JSON.toJSONString(map);
    }

    /**
     * 删除部门
     * @param id
     * @return
     */
    @RequestMapping("/deleteById")
    public JSONResult deleteById(int id){
        //删除成功
        if(deptService.removeById(id)){
            return SystemConstant.DELETE_SUCCESS;
        }
        //删除失败
        return SystemConstant.DELETE_ERROR;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值