搭建项目环境
创建项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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目录下,如下图所示
2.运行测试是否能够正确访问首页及登录页面
复制登录页面
将resources/page/login目录下的login.html页面复制到resources文件夹下,如图所示
修改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类:
- User实体类
- UserMapper接口
- UserMapper.xml映射文件
- UserService接口
- UserServiceImpl实现类
- 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类:
- Permission实体类
- PermissionMapper接口
- PermissionMapper.xml映射文件
- PermissionService接口
- PermissionServiceImpl实现类
- 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类:
- Log实体类
- LogMapper接口
- LogMapper.xml映射文件
- LogService接口
- LogServiceImpl实现类
- LogController控制器
修改Log类
- 将属性的LocalDateTime数据类型改成java.util.Date日期类型
- 生成无参带参构造方法
//无参构造方法
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类:
- Notice实体类
- NoticeMapper接口
- NoticeMapper.xml映射文件
- NoticeService接口
- NoticeServiceImpl实现类
- 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类:
- Dept实体类
- DeptMapper接口
- DeptMapper.xml映射文件
- DeptService接口
- DeptServiceImpl实现类
- 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;
}