├── vueadmin-vue ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── assets │ │ ├── logo.png │ │ └── MarkerHub.jpg │ ├── views │ │ ├── Index.vue │ │ ├── inc │ │ │ ├── SideMenu.vue │ │ │ └── Tabs.vue │ │ ├── Home.vue │ │ ├── UserCenter.vue │ │ ├── Login.vue │ │ └── sys │ │ │ ├── Menu.vue │ │ │ ├── Role.vue │ │ │ └── User.vue │ ├── globalFun.js │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ └── menus.js │ ├── main.js │ ├── App.vue │ ├── axios.js │ ├── router │ │ └── index.js │ └── mock.js ├── babel.config.js ├── README.md └── package.json ├── vueadmin-java ├── Dockerfile ├── src │ ├── main │ │ ├── resources │ │ │ ├── mapper │ │ │ │ ├── SysMenuMapper.xml │ │ │ │ ├── SysRoleMapper.xml │ │ │ │ ├── SysRoleMenuMapper.xml │ │ │ │ ├── SysUserRoleMapper.xml │ │ │ │ └── SysUserMapper.xml │ │ │ └── application.yml │ │ └── java │ │ │ └── com │ │ │ └── markerhub │ │ │ ├── common │ │ │ ├── exception │ │ │ │ ├── CaptchaException.java │ │ │ │ └── GlobalExceptionHandler.java │ │ │ ├── dto │ │ │ │ ├── PassDto.java │ │ │ │ └── SysMenuDto.java │ │ │ └── lang │ │ │ │ ├── Const.java │ │ │ │ └── Result.java │ │ │ ├── mapper │ │ │ ├── SysMenuMapper.java │ │ │ ├── SysRoleMapper.java │ │ │ ├── SysRoleMenuMapper.java │ │ │ ├── SysUserRoleMapper.java │ │ │ └── SysUserMapper.java │ │ │ ├── service │ │ │ ├── SysRoleMenuService.java │ │ │ ├── SysUserRoleService.java │ │ │ ├── SysRoleService.java │ │ │ ├── SysMenuService.java │ │ │ ├── impl │ │ │ │ ├── SysRoleMenuServiceImpl.java │ │ │ │ ├── SysUserRoleServiceImpl.java │ │ │ │ ├── SysRoleServiceImpl.java │ │ │ │ ├── SysMenuServiceImpl.java │ │ │ │ └── SysUserServiceImpl.java │ │ │ └── SysUserService.java │ │ │ ├── VueadminJavaApplication.java │ │ │ ├── entity │ │ │ ├── BaseEntity.java │ │ │ ├── SysUserRole.java │ │ │ ├── SysRoleMenu.java │ │ │ ├── SysRole.java │ │ │ ├── SysUser.java │ │ │ └── SysMenu.java │ │ │ ├── config │ │ │ ├── KaptchaConfig.java │ │ │ ├── MybatisPlusConfig.java │ │ │ ├── RedisConfig.java │ │ │ ├── CorsConfig.java │ │ │ └── SecurityConfig.java │ │ │ ├── controller │ │ │ ├── BaseController.java │ │ │ ├── TestController.java │ │ │ ├── AuthController.java │ │ │ ├── SysMenuController.java │ │ │ ├── SysRoleController.java │ │ │ └── SysUserController.java │ │ │ ├── security │ │ │ ├── LoginFailureHandler.java │ │ │ ├── JwtAuthenticationEntryPoint.java │ │ │ ├── JwtAccessDeniedHandler.java │ │ │ ├── LoginSuccessHandler.java │ │ │ ├── JwtLogoutSuccessHandler.java │ │ │ ├── UserDetailServiceImpl.java │ │ │ ├── CaptchaFilter.java │ │ │ ├── JwtAuthenticationFilter.java │ │ │ └── AccountUser.java │ │ │ ├── utils │ │ │ ├── JwtUtils.java │ │ │ └── RedisUtil.java │ │ │ └── CodeGenerator.java │ └── test │ │ └── java │ │ └── com │ │ └── markerhub │ │ └── VueadminJavaApplicationTests.java ├── docker-compose.yml ├── pom.xml └── 数据库脚本 - vueadmin.sql ├── .gitignore └── README.md /vueadmin-vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkerHub/VueAdmin/HEAD/vueadmin-vue/public/favicon.ico -------------------------------------------------------------------------------- /vueadmin-vue/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkerHub/VueAdmin/HEAD/vueadmin-vue/src/assets/logo.png -------------------------------------------------------------------------------- /vueadmin-vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /vueadmin-vue/src/assets/MarkerHub.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkerHub/VueAdmin/HEAD/vueadmin-vue/src/assets/MarkerHub.jpg -------------------------------------------------------------------------------- /vueadmin-java/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM java:8 2 | 3 | EXPOSE 8085 4 | 5 | ADD vueadmin-java-0.0.1-SNAPSHOT.jar app.jar 6 | RUN bash -c 'touch /app.jar' 7 | 8 | ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=link"] -------------------------------------------------------------------------------- /vueadmin-vue/src/views/Index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /vueadmin-vue/src/globalFun.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | 3 | Vue.mixin({ 4 | methods: { 5 | hasAuth(perm) { 6 | var authority = this.$store.state.menus.permList 7 | 8 | return authority.indexOf(perm) > -1 9 | } 10 | } 11 | }) -------------------------------------------------------------------------------- /vueadmin-java/src/main/resources/mapper/SysMenuMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/resources/mapper/SysRoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/resources/mapper/SysRoleMenuMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/resources/mapper/SysUserRoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vueadmin-java/src/test/java/com/markerhub/VueadminJavaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.markerhub; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class VueadminJavaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/common/exception/CaptchaException.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.common.exception; 2 | 3 | import org.springframework.security.core.AuthenticationException; 4 | 5 | public class CaptchaException extends AuthenticationException { 6 | 7 | public CaptchaException(String msg) { 8 | super(msg); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /vueadmin-vue/README.md: -------------------------------------------------------------------------------- 1 | # vueadmin-vue 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/mapper/SysMenuMapper.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.mapper; 2 | 3 | import com.markerhub.entity.SysMenu; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * Mapper 接口 9 | *

10 | * 11 | * @author 我的公众号:MarkerHub 12 | * @since 2021-04-05 13 | */ 14 | public interface SysMenuMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/mapper/SysRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.mapper; 2 | 3 | import com.markerhub.entity.SysRole; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * Mapper 接口 9 | *

10 | * 11 | * @author 我的公众号:MarkerHub 12 | * @since 2021-04-05 13 | */ 14 | public interface SysRoleMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/mapper/SysRoleMenuMapper.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.mapper; 2 | 3 | import com.markerhub.entity.SysRoleMenu; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * Mapper 接口 9 | *

10 | * 11 | * @author 我的公众号:MarkerHub 12 | * @since 2021-04-05 13 | */ 14 | public interface SysRoleMenuMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/mapper/SysUserRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.mapper; 2 | 3 | import com.markerhub.entity.SysUserRole; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * Mapper 接口 9 | *

10 | * 11 | * @author 我的公众号:MarkerHub 12 | * @since 2021-04-05 13 | */ 14 | public interface SysUserRoleMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/SysRoleMenuService.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service; 2 | 3 | import com.markerhub.entity.SysRoleMenu; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | *

8 | * 服务类 9 | *

10 | * 11 | * @author 我的公众号:MarkerHub 12 | * @since 2021-04-05 13 | */ 14 | public interface SysRoleMenuService extends IService { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/SysUserRoleService.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service; 2 | 3 | import com.markerhub.entity.SysUserRole; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | *

8 | * 服务类 9 | *

10 | * 11 | * @author 我的公众号:MarkerHub 12 | * @since 2021-04-05 13 | */ 14 | public interface SysUserRoleService extends IService { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vueadmin-java/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | mysql: 4 | image: mysql:5.7.27 5 | ports: 6 | - 3306:3306 7 | environment: # 指定用户root的密码 8 | - MYSQL_ROOT_PASSWORD=admin 9 | redis: 10 | image: redis:latest 11 | vueadmin: 12 | image: vueadmin:latest 13 | build: . # 表示以当前目录下的Dockerfile开始构建镜像 14 | ports: 15 | - 8085:8081 16 | depends_on: 17 | - mysql 18 | - redis -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/VueadminJavaApplication.java: -------------------------------------------------------------------------------- 1 | package com.markerhub; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class VueadminJavaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(VueadminJavaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/common/dto/PassDto.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.common.dto; 2 | 3 | import lombok.Data; 4 | 5 | import javax.validation.constraints.NotBlank; 6 | import java.io.Serializable; 7 | 8 | @Data 9 | public class PassDto implements Serializable { 10 | 11 | @NotBlank(message = "新密码不能为空") 12 | private String password; 13 | 14 | @NotBlank(message = "旧密码不能为空") 15 | private String currentPass; 16 | } 17 | -------------------------------------------------------------------------------- /vueadmin-vue/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import menus from "./modules/menus"; 4 | 5 | Vue.use(Vuex) 6 | 7 | export default new Vuex.Store({ 8 | state: { 9 | token: '' 10 | 11 | }, 12 | mutations: { 13 | 14 | SET_TOKEN: (state, token) => { 15 | state.token = token 16 | localStorage.setItem("token", token) 17 | }, 18 | 19 | 20 | }, 21 | actions: {}, 22 | modules: { 23 | menus 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/SysRoleService.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service; 2 | 3 | import com.markerhub.entity.SysRole; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 服务类 11 | *

12 | * 13 | * @author 我的公众号:MarkerHub 14 | * @since 2021-04-05 15 | */ 16 | public interface SysRoleService extends IService { 17 | 18 | List listRolesByUserId(Long userId); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/common/lang/Const.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.common.lang; 2 | 3 | public class Const { 4 | 5 | public final static String CAPTCHA_KEY = "captcha"; 6 | 7 | public final static Integer STATUS_ON = 0; 8 | public final static Integer STATUS_OFF = 1; 9 | 10 | public static final String DEFULT_PASSWORD = "888888"; 11 | public static final String DEFULT_AVATAR = "https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg"; 12 | } 13 | -------------------------------------------------------------------------------- /vueadmin-vue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | 6 | import Element from "element-ui" 7 | import "element-ui/lib/theme-chalk/index.css" 8 | 9 | import axios from './axios' 10 | import global from './globalFun' 11 | 12 | Vue.prototype.$axios = axios // 13 | Vue.config.productionTip = false 14 | 15 | // require("./mock.js") 16 | 17 | Vue.use(Element) 18 | 19 | new Vue({ 20 | router, 21 | store, 22 | render: h => h(App) 23 | }).$mount('#app') 24 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/entity/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.time.LocalDateTime; 9 | 10 | @Data 11 | public class BaseEntity implements Serializable { 12 | 13 | @TableId(value = "id", type = IdType.AUTO) 14 | private Long id; 15 | 16 | private LocalDateTime created; 17 | private LocalDateTime updated; 18 | 19 | private Integer statu; 20 | } 21 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/SysMenuService.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service; 2 | 3 | import com.markerhub.common.dto.SysMenuDto; 4 | import com.markerhub.entity.SysMenu; 5 | import com.baomidou.mybatisplus.extension.service.IService; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 服务类 12 | *

13 | * 14 | * @author 我的公众号:MarkerHub 15 | * @since 2021-04-05 16 | */ 17 | public interface SysMenuService extends IService { 18 | 19 | List getCurrentUserNav(); 20 | 21 | List tree(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | # DataSource Config 4 | spring: 5 | datasource: 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | url: jdbc:mysql://localhost:3306/vueadmin?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai 8 | username: root 9 | password: admin 10 | # security: 11 | # user: 12 | # name: user 13 | # password: 111111 14 | mybatis-plus: 15 | mapper-locations: classpath*:/mapper/**Mapper.xml 16 | markerhub: 17 | jwt: 18 | header: Authorization 19 | expire: 604800 #7天,秒单位 20 | secret: ji8n3439n439n43ld9ne9343fdfer49h -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/mapper/SysUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.mapper; 2 | 3 | import com.markerhub.entity.SysUser; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | *

12 | * Mapper 接口 13 | *

14 | * 15 | * @author 我的公众号:MarkerHub 16 | * @since 2021-04-05 17 | */ 18 | @Repository 19 | public interface SysUserMapper extends BaseMapper { 20 | 21 | List getNavMenuIds(Long userId); 22 | 23 | List listByMenuId(Long menuId); 24 | } 25 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/entity/SysUserRole.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | 8 | /** 9 | *

10 | * 11 | *

12 | * 13 | * @author 我的公众号:MarkerHub 14 | * @since 2021-04-05 15 | */ 16 | @Data 17 | public class SysUserRole { 18 | 19 | private static final long serialVersionUID = 1L; 20 | 21 | @TableId(value = "id", type = IdType.AUTO) 22 | private Long id; 23 | 24 | private Long userId; 25 | 26 | private Long roleId; 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/impl/SysRoleMenuServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service.impl; 2 | 3 | import com.markerhub.entity.SysRoleMenu; 4 | import com.markerhub.mapper.SysRoleMenuMapper; 5 | import com.markerhub.service.SysRoleMenuService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | *

11 | * 服务实现类 12 | *

13 | * 14 | * @author 我的公众号:MarkerHub 15 | * @since 2021-04-05 16 | */ 17 | @Service 18 | public class SysRoleMenuServiceImpl extends ServiceImpl implements SysRoleMenuService { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/impl/SysUserRoleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service.impl; 2 | 3 | import com.markerhub.entity.SysUserRole; 4 | import com.markerhub.mapper.SysUserRoleMapper; 5 | import com.markerhub.service.SysUserRoleService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | *

11 | * 服务实现类 12 | *

13 | * 14 | * @author 我的公众号:MarkerHub 15 | * @since 2021-04-05 16 | */ 17 | @Service 18 | public class SysUserRoleServiceImpl extends ServiceImpl implements SysUserRoleService { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/entity/SysRoleMenu.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.entity; 2 | 3 | 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | 9 | /** 10 | *

11 | * 12 | *

13 | * 14 | * @author 我的公众号:MarkerHub 15 | * @since 2021-04-05 16 | */ 17 | @Data 18 | public class SysRoleMenu { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | @TableId(value = "id", type = IdType.AUTO) 23 | private Long id; 24 | 25 | private Long roleId; 26 | 27 | private Long menuId; 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/SysUserService.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service; 2 | 3 | import com.markerhub.entity.SysUser; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | *

8 | * 服务类 9 | *

10 | * 11 | * @author 我的公众号:MarkerHub 12 | * @since 2021-04-05 13 | */ 14 | public interface SysUserService extends IService { 15 | 16 | SysUser getByUsername(String username); 17 | 18 | String getUserAuthorityInfo(Long userId); 19 | 20 | void clearUserAuthorityInfo(String username); 21 | 22 | void clearUserAuthorityInfoByRoleId(Long roleId); 23 | 24 | void clearUserAuthorityInfoByMenuId(Long menuId); 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /vueadmin-vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /vueadmin-vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 30 | 31 | 40 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/common/dto/SysMenuDto.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.common.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * { 11 | * name: 'SysUser', 12 | * title: '用户管理', 13 | * icon: 'el-icon-s-custom', 14 | * path: '/sys/users', 15 | * component: 'sys/User', 16 | * children: [] 17 | * }, 18 | */ 19 | @Data 20 | public class SysMenuDto implements Serializable { 21 | 22 | private Long id; 23 | private String name; 24 | private String title; 25 | private String icon; 26 | private String path; 27 | private String component; 28 | private List children = new ArrayList<>(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /vueadmin-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vueadmin-vue", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "axios": "^0.21.1", 11 | "core-js": "^3.6.5", 12 | "element-ui": "^2.15.0", 13 | "mockjs": "^1.1.0", 14 | "qs": "^6.10.1", 15 | "vue": "^2.6.11", 16 | "vue-router": "^3.2.0", 17 | "vuex": "^3.4.0" 18 | }, 19 | "devDependencies": { 20 | "@vue/cli-plugin-babel": "~4.5.0", 21 | "@vue/cli-plugin-router": "~4.5.0", 22 | "@vue/cli-plugin-vuex": "~4.5.0", 23 | "@vue/cli-service": "~4.5.0", 24 | "mockjs": "^1.1.0", 25 | "vue-template-compiler": "^2.6.11" 26 | }, 27 | "browserslist": [ 28 | "> 1%", 29 | "last 2 versions", 30 | "not dead" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/common/lang/Result.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.common.lang; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | @Data 8 | public class Result implements Serializable { 9 | 10 | private int code; 11 | private String msg; 12 | private Object data; 13 | 14 | public static Result succ(Object data) { 15 | return succ(200, "操作成功", data); 16 | } 17 | 18 | public static Result succ(int code, String msg, Object data) { 19 | Result r = new Result(); 20 | r.setCode(code); 21 | r.setMsg(msg); 22 | r.setData(data); 23 | return r; 24 | } 25 | 26 | public static Result fail(String msg) { 27 | return fail(400, msg, null); 28 | } 29 | 30 | public static Result fail(int code, String msg, Object data) { 31 | Result r = new Result(); 32 | r.setCode(code); 33 | r.setMsg(msg); 34 | r.setData(data); 35 | return r; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/entity/SysRole.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableField; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | import javax.validation.constraints.NotBlank; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | *

13 | * 14 | *

15 | * 16 | * @author 我的公众号:MarkerHub 17 | * @since 2021-04-05 18 | */ 19 | @Data 20 | @EqualsAndHashCode(callSuper = true) 21 | public class SysRole extends BaseEntity { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | @NotBlank(message = "角色名称不能为空") 26 | private String name; 27 | 28 | @NotBlank(message = "角色编码不能为空") 29 | private String code; 30 | 31 | /** 32 | * 备注 33 | */ 34 | private String remark; 35 | 36 | @TableField(exist = false) 37 | private List menuIds = new ArrayList<>(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/resources/mapper/SysUserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 27 | 28 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/impl/SysRoleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.markerhub.entity.SysRole; 5 | import com.markerhub.mapper.SysRoleMapper; 6 | import com.markerhub.service.SysRoleService; 7 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | *

14 | * 服务实现类 15 | *

16 | * 17 | * @author 我的公众号:MarkerHub 18 | * @since 2021-04-05 19 | */ 20 | @Service 21 | public class SysRoleServiceImpl extends ServiceImpl implements SysRoleService { 22 | 23 | @Override 24 | public List listRolesByUserId(Long userId) { 25 | 26 | List sysRoles = this.list(new QueryWrapper() 27 | .inSql("id", "select role_id from sys_user_role where user_id = " + userId)); 28 | 29 | return sysRoles; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### VueAdmin - 基于SpringBoot+Jwt+Vue的前后端分离后台管理系统 2 | 3 | 完整教学!从0到1开发,手把手教你学会开发一个spring security + jwt + vue的前后端分离项目! 4 | 5 | 线上体验:[https://www.markerhub.com/vueadmin/](https://www.markerhub.com/vueadmin/) 6 | 7 | ### 说明: 8 | 9 | 首发公众号:MarkerHub 10 | 11 | ![](https://image-1300566513.cos.ap-guangzhou.myqcloud.com/mine/MarkerHub.jpg) 12 | 13 | 项目视频:[https://www.bilibili.com/video/BV1af4y1s7Wh/](https://www.bilibili.com/video/BV1af4y1s7Wh/) 14 | 15 | 项目文档: 16 | * 前端笔记:https://shimo.im/docs/pxwyJHgqcWjWkTKX/ 17 | * 后端笔记:https://shimo.im/docs/OnZDwoxFFL8bnP1c/ 18 | 19 | 更多项目:[https://www.markerhub.com/](https://www.markerhub.com/) 20 | 21 | ### 技术栈: 22 | springboot、spring security、myabtis plus、jwt、vue、element-ui 23 | 24 | ### 项目截图 25 | ![](https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/20210423/a1c8e24a38cf4f02bda1afb18d1ed063.png) 26 | 27 | ![](https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/20210423/7e8914009bd94fa79b603cf2476a89ac.png) 28 | 29 | ### 进群学习 30 | 31 | 加我微信 java-mindman3,记得备注【 VueAdmin 】,我会拉群! 32 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/config/KaptchaConfig.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.config; 2 | 3 | import com.google.code.kaptcha.impl.DefaultKaptcha; 4 | import com.google.code.kaptcha.util.Config; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.core.parameters.P; 8 | 9 | import java.util.Properties; 10 | 11 | @Configuration 12 | public class KaptchaConfig { 13 | 14 | @Bean 15 | DefaultKaptcha producer() { 16 | Properties properties = new Properties(); 17 | properties.put("kaptcha.border", "no"); 18 | properties.put("kaptcha.textproducer.font.color", "black"); 19 | properties.put("kaptcha.textproducer.char.space", "4"); 20 | properties.put("kaptcha.image.height", "40"); 21 | properties.put("kaptcha.image.width", "120"); 22 | properties.put("kaptcha.textproducer.font.size", "30"); 23 | 24 | Config config = new Config(properties); 25 | DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); 26 | defaultKaptcha.setConfig(config); 27 | 28 | return defaultKaptcha; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/entity/SysUser.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.entity; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import com.baomidou.mybatisplus.annotation.TableField; 8 | import lombok.Data; 9 | import lombok.EqualsAndHashCode; 10 | 11 | import javax.validation.constraints.Email; 12 | import javax.validation.constraints.NotBlank; 13 | 14 | /** 15 | *

16 | * 17 | *

18 | * 19 | * @author 我的公众号:MarkerHub 20 | * @since 2021-04-05 21 | */ 22 | @Data 23 | @EqualsAndHashCode(callSuper = true) 24 | public class SysUser extends BaseEntity { 25 | 26 | private static final long serialVersionUID = 1L; 27 | 28 | @NotBlank(message = "用户名不能为空") 29 | private String username; 30 | 31 | private String password; 32 | 33 | private String avatar; 34 | 35 | @NotBlank(message = "邮箱不能为空") 36 | @Email(message = "邮箱格式不正确") 37 | private String email; 38 | 39 | private String city; 40 | 41 | private LocalDateTime lastLogin; 42 | 43 | @TableField(exist = false) 44 | private List sysRoles = new ArrayList<>(); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/controller/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.controller; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.markerhub.service.*; 5 | import com.markerhub.utils.RedisUtil; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.ServletRequestUtils; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | 11 | public class BaseController { 12 | 13 | @Autowired 14 | HttpServletRequest req; 15 | 16 | @Autowired 17 | RedisUtil redisUtil; 18 | 19 | @Autowired 20 | SysUserService sysUserService; 21 | 22 | @Autowired 23 | SysRoleService sysRoleService; 24 | 25 | @Autowired 26 | SysMenuService sysMenuService; 27 | 28 | @Autowired 29 | SysUserRoleService sysUserRoleService; 30 | 31 | @Autowired 32 | SysRoleMenuService sysRoleMenuService; 33 | 34 | /** 35 | * 获取页面 36 | * @return 37 | */ 38 | public Page getPage() { 39 | int current = ServletRequestUtils.getIntParameter(req, "cuurent", 1); 40 | int size = ServletRequestUtils.getIntParameter(req, "size", 10); 41 | 42 | return new Page(current, size); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /vueadmin-vue/src/axios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import router from "./router"; 3 | import Element from "element-ui" 4 | 5 | axios.defaults.baseURL = "http://localhost:8081" 6 | 7 | const request = axios.create({ 8 | timeout: 5000, 9 | headers: { 10 | 'Content-Type': "application/json; charset=utf-8" 11 | } 12 | }) 13 | 14 | request.interceptors.request.use(config => { 15 | config.headers['Authorization'] = localStorage.getItem("token") 16 | return config 17 | }) 18 | 19 | request.interceptors.response.use( 20 | response => { 21 | 22 | console.log("response ->" + response) 23 | 24 | let res = response.data 25 | 26 | if (res.code === 200) { 27 | return response 28 | } else { 29 | Element.Message.error(!res.msg ? '系统异常' : res.msg) 30 | return Promise.reject(response.data.msg) 31 | } 32 | }, 33 | error => { 34 | 35 | console.log(error) 36 | 37 | if (error.response.data) { 38 | error.massage = error.response.data.msg 39 | } 40 | 41 | if (error.response.status === 401) { 42 | router.push("/login") 43 | } 44 | 45 | Element.Message.error(error.massage, {duration: 3000}) 46 | return Promise.reject(error) 47 | } 48 | ) 49 | 50 | export default request -------------------------------------------------------------------------------- /vueadmin-vue/src/store/modules/menus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default { 7 | state: { 8 | 9 | menuList: [], 10 | permList: [], 11 | 12 | hasRoutes: false, 13 | 14 | editableTabsValue: 'Index', 15 | editableTabs: [{ 16 | title: '首页', 17 | name: 'Index', 18 | }] 19 | }, 20 | mutations: { 21 | setMenuList(state, menus) { 22 | state.menuList = menus 23 | }, 24 | setPermList(state, perms) { 25 | state.permList = perms 26 | }, 27 | changeRouteStatus(state, hasRoutes) { 28 | state.hasRoutes = hasRoutes 29 | }, 30 | 31 | addTab(state, tab) { 32 | 33 | let index = state.editableTabs.findIndex(e => e.name === tab.name) 34 | 35 | if (index === -1) { 36 | state.editableTabs.push({ 37 | title: tab.title, 38 | name: tab.name, 39 | }); 40 | } 41 | 42 | state.editableTabsValue = tab.name; 43 | }, 44 | 45 | resetState: (state) => { 46 | state.menuList = [] 47 | state.permList = [] 48 | 49 | state.hasRoutes = false 50 | state.editableTabsValue = 'Index' 51 | state.editableTabs = [{ 52 | title: '首页', 53 | name: 'Index', 54 | }] 55 | } 56 | 57 | }, 58 | actions: { 59 | }, 60 | 61 | } -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/config/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.config; 2 | 3 | import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; 4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 5 | import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; 6 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; 7 | import org.mybatis.spring.annotation.MapperScan; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | @MapperScan("com.markerhub.mapper") 13 | public class MybatisPlusConfig { 14 | 15 | @Bean 16 | public MybatisPlusInterceptor mybatisPlusInterceptor() { 17 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 18 | // 分页插件 19 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 20 | // 防止全表更新插件 21 | interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); 22 | 23 | return interceptor; 24 | } 25 | 26 | @Bean 27 | public ConfigurationCustomizer configurationCustomizer() { 28 | return configuration -> configuration.setUseDeprecatedExecutor(false); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/LoginFailureHandler.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.markerhub.common.lang.Result; 5 | import org.springframework.security.core.AuthenticationException; 6 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.ServletOutputStream; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | 15 | @Component 16 | public class LoginFailureHandler implements AuthenticationFailureHandler { 17 | 18 | @Override 19 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { 20 | 21 | response.setContentType("application/json;charset=UTF-8"); 22 | ServletOutputStream outputStream = response.getOutputStream(); 23 | 24 | Result result = Result.fail("用户名或密码错误"); 25 | 26 | outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8")); 27 | 28 | outputStream.flush(); 29 | outputStream.close(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.controller; 2 | 3 | import com.markerhub.common.lang.Result; 4 | import com.markerhub.service.SysUserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.access.prepost.PreAuthorize; 7 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class TestController { 13 | 14 | @Autowired 15 | SysUserService sysUserService; 16 | 17 | @Autowired 18 | BCryptPasswordEncoder bCryptPasswordEncoder; 19 | 20 | @PreAuthorize("hasRole('admin')") 21 | @GetMapping("/test") 22 | public Result test() { 23 | return Result.succ(sysUserService.list()); 24 | } 25 | 26 | // 普通用户、超级管理员 27 | @PreAuthorize("hasAuthority('sys:user:list')") 28 | @GetMapping("/test/pass") 29 | public Result pass() { 30 | 31 | // 加密后密码 32 | String password = bCryptPasswordEncoder.encode("111111"); 33 | 34 | boolean matches = bCryptPasswordEncoder.matches("111111", password); 35 | 36 | System.out.println("匹配结果:" + matches); 37 | 38 | return Result.succ(password); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/JwtAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.markerhub.common.lang.Result; 5 | import org.springframework.security.core.AuthenticationException; 6 | import org.springframework.security.web.AuthenticationEntryPoint; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.ServletOutputStream; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | 15 | @Component 16 | public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { 17 | 18 | @Override 19 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 20 | 21 | response.setContentType("application/json;charset=UTF-8"); 22 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 23 | ServletOutputStream outputStream = response.getOutputStream(); 24 | 25 | Result result = Result.fail("请先登录"); 26 | 27 | outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8")); 28 | 29 | outputStream.flush(); 30 | outputStream.close(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/JwtAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.markerhub.common.lang.Result; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.security.web.access.AccessDeniedHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.ServletOutputStream; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | 15 | @Component 16 | public class JwtAccessDeniedHandler implements AccessDeniedHandler { 17 | 18 | @Override 19 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 20 | 21 | response.setContentType("application/json;charset=UTF-8"); 22 | response.setStatus(HttpServletResponse.SC_FORBIDDEN); 23 | 24 | ServletOutputStream outputStream = response.getOutputStream(); 25 | 26 | Result result = Result.fail(accessDeniedException.getMessage()); 27 | 28 | outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8")); 29 | 30 | outputStream.flush(); 31 | outputStream.close(); 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/utils/JwtUtils.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.utils; 2 | 3 | import io.jsonwebtoken.*; 4 | import lombok.Data; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @Component 12 | @ConfigurationProperties(prefix = "markerhub.jwt") 13 | public class JwtUtils { 14 | 15 | private long expire; 16 | private String secret; 17 | private String header; 18 | 19 | // 生成jwt 20 | public String generateToken(String username) { 21 | 22 | Date nowDate = new Date(); 23 | Date expireDate = new Date(nowDate.getTime() + 1000 * expire); 24 | 25 | return Jwts.builder() 26 | .setHeaderParam("typ", "JWT") 27 | .setSubject(username) 28 | .setIssuedAt(nowDate) 29 | .setExpiration(expireDate)// 7天過期 30 | .signWith(SignatureAlgorithm.HS512, secret) 31 | .compact(); 32 | } 33 | 34 | // 解析jwt 35 | public Claims getClaimByToken(String jwt) { 36 | try { 37 | return Jwts.parser() 38 | .setSigningKey(secret) 39 | .parseClaimsJws(jwt) 40 | .getBody(); 41 | } catch (Exception e) { 42 | return null; 43 | } 44 | } 45 | 46 | // jwt是否过期 47 | public boolean isTokenExpired(Claims claims) { 48 | return claims.getExpiration().before(new Date()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/config/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.config; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.RedisConnectionFactory; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 9 | import org.springframework.data.redis.serializer.StringRedisSerializer; 10 | 11 | @Configuration 12 | public class RedisConfig { 13 | 14 | @Bean 15 | RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 16 | 17 | RedisTemplate redisTemplate = new RedisTemplate(); 18 | redisTemplate.setConnectionFactory(redisConnectionFactory); 19 | 20 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); 21 | jackson2JsonRedisSerializer.setObjectMapper(new ObjectMapper()); 22 | 23 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 24 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 25 | 26 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 27 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 28 | 29 | return redisTemplate; 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/config/CorsConfig.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.cors.CorsConfiguration; 6 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 7 | import org.springframework.web.filter.CorsFilter; 8 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | 11 | @Configuration 12 | public class CorsConfig implements WebMvcConfigurer { 13 | 14 | private CorsConfiguration buildConfig() { 15 | CorsConfiguration corsConfiguration = new CorsConfiguration(); 16 | corsConfiguration.addAllowedOrigin("*"); 17 | corsConfiguration.addAllowedHeader("*"); 18 | corsConfiguration.addAllowedMethod("*"); 19 | corsConfiguration.addExposedHeader("Authorization"); 20 | return corsConfiguration; 21 | } 22 | 23 | @Bean 24 | public CorsFilter corsFilter() { 25 | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 26 | source.registerCorsConfiguration("/**", buildConfig()); 27 | return new CorsFilter(source); 28 | } 29 | 30 | @Override 31 | public void addCorsMappings(CorsRegistry registry) { 32 | registry.addMapping("/**") 33 | .allowedOrigins("*") 34 | // .allowCredentials(true) 35 | .allowedMethods("GET", "POST", "DELETE", "PUT") 36 | .maxAge(3600); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/LoginSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.markerhub.common.lang.Result; 5 | import com.markerhub.utils.JwtUtils; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.servlet.ServletException; 12 | import javax.servlet.ServletOutputStream; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.io.IOException; 16 | 17 | @Component 18 | public class LoginSuccessHandler implements AuthenticationSuccessHandler { 19 | 20 | @Autowired 21 | JwtUtils jwtUtils; 22 | 23 | @Override 24 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 25 | response.setContentType("application/json;charset=UTF-8"); 26 | ServletOutputStream outputStream = response.getOutputStream(); 27 | 28 | // 生成jwt,并放置到请求头中 29 | String jwt = jwtUtils.generateToken(authentication.getName()); 30 | response.setHeader(jwtUtils.getHeader(), jwt); 31 | 32 | Result result = Result.succ(""); 33 | 34 | outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8")); 35 | 36 | outputStream.flush(); 37 | outputStream.close(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/entity/SysMenu.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableField; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | import javax.validation.constraints.NotBlank; 8 | import javax.validation.constraints.NotNull; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | *

14 | * 15 | *

16 | * 17 | * @author 我的公众号:MarkerHub 18 | * @since 2021-04-05 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = true) 22 | public class SysMenu extends BaseEntity { 23 | 24 | private static final long serialVersionUID = 1L; 25 | 26 | /** 27 | * 父菜单ID,一级菜单为0 28 | */ 29 | @NotNull(message = "上级菜单不能为空") 30 | private Long parentId; 31 | 32 | @NotBlank(message = "菜单名称不能为空") 33 | private String name; 34 | 35 | /** 36 | * 菜单URL 37 | */ 38 | private String path; 39 | 40 | /** 41 | * 授权(多个用逗号分隔,如:user:list,user:create) 42 | */ 43 | @NotBlank(message = "菜单授权码不能为空") 44 | private String perms; 45 | 46 | private String component; 47 | 48 | /** 49 | * 类型 0:目录 1:菜单 2:按钮 50 | */ 51 | @NotNull(message = "菜单类型不能为空") 52 | private Integer type; 53 | 54 | /** 55 | * 菜单图标 56 | */ 57 | private String icon; 58 | 59 | /** 60 | * 排序 61 | */ 62 | @TableField("orderNum") 63 | private Integer orderNum; 64 | 65 | @TableField(exist = false) 66 | private List children = new ArrayList<>(); 67 | } 68 | -------------------------------------------------------------------------------- /vueadmin-vue/src/views/inc/SideMenu.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 60 | 61 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/JwtLogoutSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.markerhub.common.lang.Result; 5 | import com.markerhub.utils.JwtUtils; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 9 | import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.servlet.ServletException; 13 | import javax.servlet.ServletOutputStream; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | import java.io.IOException; 17 | 18 | @Component 19 | public class JwtLogoutSuccessHandler implements LogoutSuccessHandler { 20 | 21 | @Autowired 22 | JwtUtils jwtUtils; 23 | 24 | @Override 25 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 26 | 27 | if (authentication != null) { 28 | new SecurityContextLogoutHandler().logout(request, response, authentication); 29 | } 30 | 31 | response.setContentType("application/json;charset=UTF-8"); 32 | ServletOutputStream outputStream = response.getOutputStream(); 33 | 34 | response.setHeader(jwtUtils.getHeader(), ""); 35 | 36 | Result result = Result.succ(""); 37 | 38 | outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8")); 39 | 40 | outputStream.flush(); 41 | outputStream.close(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/UserDetailServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import com.markerhub.entity.SysUser; 4 | import com.markerhub.service.SysUserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.authority.AuthorityUtils; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.core.userdetails.UserDetailsService; 10 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | @Service 16 | public class UserDetailServiceImpl implements UserDetailsService { 17 | 18 | @Autowired 19 | SysUserService sysUserService; 20 | 21 | @Override 22 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 23 | 24 | SysUser sysUser = sysUserService.getByUsername(username); 25 | if (sysUser == null) { 26 | throw new UsernameNotFoundException("用户名或密码不正确"); 27 | } 28 | return new AccountUser(sysUser.getId(), sysUser.getUsername(), sysUser.getPassword(), getUserAuthority(sysUser.getId())); 29 | } 30 | 31 | /** 32 | * 获取用户权限信息(角色、菜单权限) 33 | * @param userId 34 | * @return 35 | */ 36 | public List getUserAuthority(Long userId){ 37 | 38 | // 角色(ROLE_admin)、菜单操作权限 sys:user:list 39 | String authority = sysUserService.getUserAuthorityInfo(userId); // ROLE_admin,ROLE_normal,sys:user:list,.... 40 | 41 | return AuthorityUtils.commaSeparatedStringToAuthorityList(authority); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/common/exception/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.common.exception; 2 | 3 | import com.markerhub.common.lang.Result; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.validation.BindingResult; 7 | import org.springframework.validation.ObjectError; 8 | import org.springframework.web.bind.MethodArgumentNotValidException; 9 | import org.springframework.web.bind.annotation.ExceptionHandler; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | import org.springframework.web.bind.annotation.RestControllerAdvice; 12 | 13 | @Slf4j 14 | @RestControllerAdvice 15 | public class GlobalExceptionHandler { 16 | 17 | // 18 | 19 | // 实体校验异常捕获 20 | @ResponseStatus(HttpStatus.BAD_REQUEST) 21 | @ExceptionHandler(value = MethodArgumentNotValidException.class) 22 | public Result handler(MethodArgumentNotValidException e) { 23 | 24 | BindingResult result = e.getBindingResult(); 25 | ObjectError objectError = result.getAllErrors().stream().findFirst().get(); 26 | 27 | log.error("实体校验异常:----------------{}", objectError.getDefaultMessage()); 28 | return Result.fail(objectError.getDefaultMessage()); 29 | } 30 | 31 | @ResponseStatus(HttpStatus.BAD_REQUEST) 32 | @ExceptionHandler(value = IllegalArgumentException.class) 33 | public Result handler(IllegalArgumentException e) { 34 | log.error("Assert异常:----------------{}", e.getMessage()); 35 | return Result.fail(e.getMessage()); 36 | } 37 | 38 | @ResponseStatus(HttpStatus.BAD_REQUEST) 39 | @ExceptionHandler(value = RuntimeException.class) 40 | public Result handler(RuntimeException e) { 41 | log.error("运行时异常:----------------{}", e.getMessage()); 42 | return Result.fail(e.getMessage()); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /vueadmin-vue/src/views/inc/Tabs.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 74 | 75 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/CaptchaFilter.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import com.baomidou.mybatisplus.core.toolkit.StringUtils; 4 | import com.markerhub.common.exception.CaptchaException; 5 | import com.markerhub.common.lang.Const; 6 | import com.markerhub.utils.RedisUtil; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.web.filter.OncePerRequestFilter; 10 | 11 | import javax.servlet.FilterChain; 12 | import javax.servlet.ServletException; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.io.IOException; 16 | 17 | @Component 18 | public class CaptchaFilter extends OncePerRequestFilter { 19 | 20 | @Autowired 21 | RedisUtil redisUtil; 22 | 23 | @Autowired 24 | LoginFailureHandler loginFailureHandler; 25 | 26 | @Override 27 | protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { 28 | 29 | String url = httpServletRequest.getRequestURI(); 30 | 31 | if ("/login".equals(url) && httpServletRequest.getMethod().equals("POST")) { 32 | 33 | try{ 34 | // 校验验证码 35 | validate(httpServletRequest); 36 | } catch (CaptchaException e) { 37 | 38 | // 交给认证失败处理器 39 | loginFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); 40 | } 41 | } 42 | 43 | filterChain.doFilter(httpServletRequest, httpServletResponse); 44 | } 45 | 46 | // 校验验证码逻辑 47 | private void validate(HttpServletRequest httpServletRequest) { 48 | 49 | String code = httpServletRequest.getParameter("code"); 50 | String key = httpServletRequest.getParameter("token"); 51 | 52 | if (StringUtils.isBlank(code) || StringUtils.isBlank(key)) { 53 | throw new CaptchaException("验证码错误"); 54 | } 55 | 56 | if (!code.equals(redisUtil.hget(Const.CAPTCHA_KEY, key))) { 57 | throw new CaptchaException("验证码错误"); 58 | } 59 | 60 | // 一次性使用 61 | redisUtil.hdel(Const.CAPTCHA_KEY, key); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/controller/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.controller; 2 | 3 | import cn.hutool.core.lang.UUID; 4 | import cn.hutool.core.map.MapUtil; 5 | import com.google.code.kaptcha.Producer; 6 | import com.markerhub.common.lang.Const; 7 | import com.markerhub.common.lang.Result; 8 | import com.markerhub.entity.SysUser; 9 | import com.markerhub.service.SysUserService; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | import sun.misc.BASE64Encoder; 14 | 15 | import javax.imageio.ImageIO; 16 | import java.awt.image.BufferedImage; 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.IOException; 19 | import java.security.Principal; 20 | 21 | @RestController 22 | public class AuthController extends BaseController{ 23 | 24 | @Autowired 25 | Producer producer; 26 | 27 | @GetMapping("/captcha") 28 | public Result captcha() throws IOException { 29 | 30 | String key = UUID.randomUUID().toString(); 31 | String code = producer.createText(); 32 | 33 | // 为了测试 34 | key = "aaaaa"; 35 | code = "11111"; 36 | 37 | BufferedImage image = producer.createImage(code); 38 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 39 | ImageIO.write(image, "jpg", outputStream); 40 | 41 | BASE64Encoder encoder = new BASE64Encoder(); 42 | String str = "data:image/jpeg;base64,"; 43 | 44 | String base64Img = str + encoder.encode(outputStream.toByteArray()); 45 | 46 | redisUtil.hset(Const.CAPTCHA_KEY, key, code, 120); 47 | 48 | return Result.succ( 49 | MapUtil.builder() 50 | .put("token", key) 51 | .put("captchaImg", base64Img) 52 | .build() 53 | 54 | ); 55 | } 56 | 57 | /** 58 | * 获取用户信息接口 59 | * @param principal 60 | * @return 61 | */ 62 | @GetMapping("/sys/userInfo") 63 | public Result userInfo(Principal principal) { 64 | 65 | SysUser sysUser = sysUserService.getByUsername(principal.getName()); 66 | 67 | return Result.succ(MapUtil.builder() 68 | .put("id", sysUser.getId()) 69 | .put("username", sysUser.getUsername()) 70 | .put("avatar", sysUser.getAvatar()) 71 | .put("created", sysUser.getCreated()) 72 | .map() 73 | ); 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/JwtAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.markerhub.entity.SysUser; 5 | import com.markerhub.service.SysUserService; 6 | import com.markerhub.utils.JwtUtils; 7 | import io.jsonwebtoken.Claims; 8 | import io.jsonwebtoken.JwtException; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.security.authentication.AuthenticationManager; 11 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 12 | import org.springframework.security.core.context.SecurityContextHolder; 13 | import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; 14 | 15 | import javax.servlet.FilterChain; 16 | import javax.servlet.ServletException; 17 | import javax.servlet.http.HttpServletRequest; 18 | import javax.servlet.http.HttpServletResponse; 19 | import java.io.IOException; 20 | 21 | public class JwtAuthenticationFilter extends BasicAuthenticationFilter { 22 | 23 | @Autowired 24 | JwtUtils jwtUtils; 25 | 26 | @Autowired 27 | UserDetailServiceImpl userDetailService; 28 | 29 | @Autowired 30 | SysUserService sysUserService; 31 | 32 | public JwtAuthenticationFilter(AuthenticationManager authenticationManager) { 33 | super(authenticationManager); 34 | } 35 | 36 | @Override 37 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { 38 | 39 | String jwt = request.getHeader(jwtUtils.getHeader()); 40 | if (StrUtil.isBlankOrUndefined(jwt)) { 41 | chain.doFilter(request, response); 42 | return; 43 | } 44 | 45 | Claims claim = jwtUtils.getClaimByToken(jwt); 46 | if (claim == null) { 47 | throw new JwtException("token 异常"); 48 | } 49 | if (jwtUtils.isTokenExpired(claim)) { 50 | throw new JwtException("token已过期"); 51 | } 52 | 53 | String username = claim.getSubject(); 54 | // 获取用户的权限等信息 55 | 56 | SysUser sysUser = sysUserService.getByUsername(username); 57 | UsernamePasswordAuthenticationToken token 58 | = new UsernamePasswordAuthenticationToken(username, null, userDetailService.getUserAuthority(sysUser.getId())); 59 | 60 | SecurityContextHolder.getContext().setAuthentication(token); 61 | 62 | chain.doFilter(request, response); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/security/AccountUser.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.security; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | import org.springframework.security.core.userdetails.UserDetails; 5 | import org.springframework.util.Assert; 6 | 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.Set; 10 | 11 | public class AccountUser implements UserDetails { 12 | 13 | private Long userId; 14 | 15 | private String password; 16 | 17 | private final String username; 18 | 19 | private final Collection authorities; 20 | 21 | private final boolean accountNonExpired; 22 | 23 | private final boolean accountNonLocked; 24 | 25 | private final boolean credentialsNonExpired; 26 | 27 | private final boolean enabled; 28 | 29 | public AccountUser(Long userId, String username, String password, Collection authorities) { 30 | this(userId, username, password, true, true, true, true, authorities); 31 | } 32 | 33 | 34 | public AccountUser(Long userId, String username, String password, boolean enabled, boolean accountNonExpired, 35 | boolean credentialsNonExpired, boolean accountNonLocked, 36 | Collection authorities) { 37 | Assert.isTrue(username != null && !"".equals(username) && password != null, 38 | "Cannot pass null or empty values to constructor"); 39 | this.userId = userId; 40 | this.username = username; 41 | this.password = password; 42 | this.enabled = enabled; 43 | this.accountNonExpired = accountNonExpired; 44 | this.credentialsNonExpired = credentialsNonExpired; 45 | this.accountNonLocked = accountNonLocked; 46 | this.authorities = authorities; 47 | } 48 | 49 | 50 | @Override 51 | public Collection getAuthorities() { 52 | return this.authorities; 53 | } 54 | 55 | @Override 56 | public String getPassword() { 57 | return this.password; 58 | } 59 | 60 | @Override 61 | public String getUsername() { 62 | return this.username; 63 | } 64 | 65 | @Override 66 | public boolean isAccountNonExpired() { 67 | return this.accountNonExpired; 68 | } 69 | 70 | @Override 71 | public boolean isAccountNonLocked() { 72 | return this.accountNonLocked; 73 | } 74 | 75 | @Override 76 | public boolean isCredentialsNonExpired() { 77 | return this.credentialsNonExpired; 78 | } 79 | 80 | @Override 81 | public boolean isEnabled() { 82 | return this.enabled; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /vueadmin-vue/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 83 | 84 | -------------------------------------------------------------------------------- /vueadmin-vue/src/views/UserCenter.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 97 | 98 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/impl/SysMenuServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service.impl; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 | import com.markerhub.common.dto.SysMenuDto; 6 | import com.markerhub.entity.SysMenu; 7 | import com.markerhub.entity.SysUser; 8 | import com.markerhub.mapper.SysMenuMapper; 9 | import com.markerhub.mapper.SysUserMapper; 10 | import com.markerhub.service.SysMenuService; 11 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 12 | import com.markerhub.service.SysUserService; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.security.core.context.SecurityContextHolder; 15 | import org.springframework.stereotype.Service; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | *

22 | * 服务实现类 23 | *

24 | * 25 | * @author 我的公众号:MarkerHub 26 | * @since 2021-04-05 27 | */ 28 | @Service 29 | public class SysMenuServiceImpl extends ServiceImpl implements SysMenuService { 30 | 31 | @Autowired 32 | SysUserService sysUserService; 33 | 34 | @Autowired 35 | SysUserMapper sysUserMapper; 36 | 37 | @Override 38 | public List getCurrentUserNav() { 39 | String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 40 | SysUser sysUser = sysUserService.getByUsername(username); 41 | 42 | List menuIds = sysUserMapper.getNavMenuIds(sysUser.getId()); 43 | List menus = this.listByIds(menuIds); 44 | 45 | // 转树状结构 46 | List menuTree = buildTreeMenu(menus); 47 | 48 | // 实体转DTO 49 | return convert(menuTree); 50 | } 51 | 52 | @Override 53 | public List tree() { 54 | // 获取所有菜单信息 55 | List sysMenus = this.list(new QueryWrapper().orderByAsc("orderNum")); 56 | 57 | // 转成树状结构 58 | return buildTreeMenu(sysMenus); 59 | } 60 | 61 | private List convert(List menuTree) { 62 | List menuDtos = new ArrayList<>(); 63 | 64 | menuTree.forEach(m -> { 65 | SysMenuDto dto = new SysMenuDto(); 66 | 67 | dto.setId(m.getId()); 68 | dto.setName(m.getPerms()); 69 | dto.setTitle(m.getName()); 70 | dto.setComponent(m.getComponent()); 71 | dto.setPath(m.getPath()); 72 | 73 | if (m.getChildren().size() > 0) { 74 | 75 | // 子节点调用当前方法进行再次转换 76 | dto.setChildren(convert(m.getChildren())); 77 | } 78 | 79 | menuDtos.add(dto); 80 | }); 81 | 82 | return menuDtos; 83 | } 84 | 85 | private List buildTreeMenu(List menus) { 86 | 87 | List finalMenus = new ArrayList<>(); 88 | 89 | // 先各自寻找到各自的孩子 90 | for (SysMenu menu : menus) { 91 | 92 | for (SysMenu e : menus) { 93 | if (menu.getId() == e.getParentId()) { 94 | menu.getChildren().add(e); 95 | } 96 | } 97 | 98 | // 提取出父节点 99 | if (menu.getParentId() == 0L) { 100 | finalMenus.add(menu); 101 | } 102 | } 103 | 104 | System.out.println(JSONUtil.toJsonStr(finalMenus)); 105 | return finalMenus; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /vueadmin-vue/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | import Index from '../views/Index.vue' 5 | import User from '../views/sys/User.vue' 6 | import Role from '../views/sys/Role.vue' 7 | import Menu from '../views/sys/Menu.vue' 8 | 9 | import axios from "../axios"; 10 | import store from "../store" 11 | import el from "element-ui/src/locale/lang/el"; 12 | 13 | Vue.use(VueRouter) 14 | 15 | const routes = [ 16 | { 17 | path: '/', 18 | name: 'Home', 19 | component: Home, 20 | children: [ 21 | { 22 | path: '/index', 23 | name: 'Index', 24 | meta: { 25 | title: "首页" 26 | }, 27 | component: Index 28 | }, 29 | { 30 | path: '/userCenter', 31 | name: 'UserCenter', 32 | meta: { 33 | title: "个人中心" 34 | }, 35 | component: () => import('@/views/UserCenter.vue') 36 | }, 37 | // { 38 | // path: '/sys/users', 39 | // name: 'SysUser', 40 | // component: User 41 | // }, 42 | // { 43 | // path: '/sys/roles', 44 | // name: 'SysRole', 45 | // component: Role 46 | // }, 47 | // { 48 | // path: '/sys/menus', 49 | // name: 'SysMenu', 50 | // component: Menu 51 | // }, 52 | ] 53 | }, 54 | 55 | { 56 | path: '/login', 57 | name: 'Login', 58 | component: () => import('@/views/Login.vue') 59 | } 60 | ] 61 | 62 | const router = new VueRouter({ 63 | mode: 'history', 64 | base: process.env.BASE_URL, 65 | routes 66 | }) 67 | 68 | router.beforeEach((to, from, next) => { 69 | 70 | let hasRoute = store.state.menus.hasRoutes 71 | 72 | let token = localStorage.getItem("token") 73 | 74 | if (to.path == '/login') { 75 | next() 76 | 77 | } else if (!token) { 78 | next({path: '/login'}) 79 | 80 | 81 | } else if(token && !hasRoute) { 82 | axios.get("/sys/menu/nav", { 83 | headers: { 84 | Authorization: localStorage.getItem("token") 85 | } 86 | }).then(res => { 87 | 88 | console.log(res.data.data) 89 | 90 | // 拿到menuList 91 | store.commit("setMenuList", res.data.data.nav) 92 | 93 | // 拿到用户权限 94 | store.commit("setPermList", res.data.data.authoritys) 95 | 96 | console.log(store.state.menus.menuList) 97 | 98 | // 动态绑定路由 99 | let newRoutes = router.options.routes 100 | 101 | res.data.data.nav.forEach(menu => { 102 | if (menu.children) { 103 | menu.children.forEach(e => { 104 | 105 | // 转成路由 106 | let route = menuToRoute(e) 107 | 108 | // 吧路由添加到路由管理中 109 | if (route) { 110 | newRoutes[0].children.push(route) 111 | } 112 | 113 | }) 114 | } 115 | }) 116 | 117 | console.log("newRoutes") 118 | console.log(newRoutes) 119 | router.addRoutes(newRoutes) 120 | 121 | hasRoute = true 122 | store.commit("changeRouteStatus", hasRoute) 123 | }) 124 | } 125 | 126 | 127 | 128 | next() 129 | }) 130 | 131 | 132 | // 导航转成路由 133 | const menuToRoute = (menu) => { 134 | 135 | if (!menu.component) { 136 | return null 137 | } 138 | 139 | let route = { 140 | name: menu.name, 141 | path: menu.path, 142 | meta: { 143 | icon: menu.icon, 144 | title: menu.title 145 | } 146 | } 147 | route.component = () => import('@/views/' + menu.component +'.vue') 148 | 149 | return route 150 | } 151 | 152 | export default router 153 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.config; 2 | 3 | import com.markerhub.security.*; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 12 | import org.springframework.security.config.http.SessionCreationPolicy; 13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 14 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 15 | 16 | @Configuration 17 | @EnableWebSecurity 18 | @EnableGlobalMethodSecurity(prePostEnabled = true) 19 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 20 | 21 | @Autowired 22 | LoginFailureHandler loginFailureHandler; 23 | 24 | @Autowired 25 | LoginSuccessHandler loginSuccessHandler; 26 | 27 | @Autowired 28 | CaptchaFilter captchaFilter; 29 | 30 | @Autowired 31 | JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; 32 | 33 | @Autowired 34 | JwtAccessDeniedHandler jwtAccessDeniedHandler; 35 | 36 | @Autowired 37 | UserDetailServiceImpl userDetailService; 38 | 39 | @Autowired 40 | JwtLogoutSuccessHandler jwtLogoutSuccessHandler; 41 | 42 | @Bean 43 | JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception { 44 | JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager()); 45 | return jwtAuthenticationFilter; 46 | } 47 | 48 | @Bean 49 | BCryptPasswordEncoder bCryptPasswordEncoder() { 50 | return new BCryptPasswordEncoder(); 51 | } 52 | 53 | private static final String[] URL_WHITELIST = { 54 | 55 | "/login", 56 | "/logout", 57 | "/captcha", 58 | "/favicon.ico", 59 | 60 | }; 61 | 62 | 63 | protected void configure(HttpSecurity http) throws Exception { 64 | 65 | http.cors().and().csrf().disable() 66 | 67 | // 登录配置 68 | .formLogin() 69 | .successHandler(loginSuccessHandler) 70 | .failureHandler(loginFailureHandler) 71 | 72 | .and() 73 | .logout() 74 | .logoutSuccessHandler(jwtLogoutSuccessHandler) 75 | 76 | // 禁用session 77 | .and() 78 | .sessionManagement() 79 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 80 | 81 | // 配置拦截规则 82 | .and() 83 | .authorizeRequests() 84 | .antMatchers(URL_WHITELIST).permitAll() 85 | .anyRequest().authenticated() 86 | 87 | // 异常处理器 88 | .and() 89 | .exceptionHandling() 90 | .authenticationEntryPoint(jwtAuthenticationEntryPoint) 91 | .accessDeniedHandler(jwtAccessDeniedHandler) 92 | 93 | // 配置自定义的过滤器 94 | .and() 95 | .addFilter(jwtAuthenticationFilter()) 96 | .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class) 97 | 98 | ; 99 | 100 | } 101 | 102 | @Override 103 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 104 | auth.userDetailsService(userDetailService); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/service/impl/SysUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.markerhub.entity.SysMenu; 6 | import com.markerhub.entity.SysRole; 7 | import com.markerhub.entity.SysUser; 8 | import com.markerhub.mapper.SysUserMapper; 9 | import com.markerhub.service.SysMenuService; 10 | import com.markerhub.service.SysRoleService; 11 | import com.markerhub.service.SysUserService; 12 | import com.markerhub.utils.RedisUtil; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Service; 15 | 16 | import java.util.List; 17 | import java.util.stream.Collectors; 18 | 19 | /** 20 | *

21 | * 服务实现类 22 | *

23 | * 24 | * @author 我的公众号:MarkerHub 25 | * @since 2021-04-05 26 | */ 27 | @Service 28 | public class SysUserServiceImpl extends ServiceImpl implements SysUserService { 29 | 30 | @Autowired 31 | SysRoleService sysRoleService; 32 | 33 | @Autowired 34 | SysUserMapper sysUserMapper; 35 | 36 | @Autowired 37 | SysMenuService sysMenuService; 38 | 39 | @Autowired 40 | RedisUtil redisUtil; 41 | 42 | @Override 43 | public SysUser getByUsername(String username) { 44 | return getOne(new QueryWrapper().eq("username", username)); 45 | } 46 | 47 | @Override 48 | public String getUserAuthorityInfo(Long userId) { 49 | 50 | SysUser sysUser = sysUserMapper.selectById(userId); 51 | 52 | // ROLE_admin,ROLE_normal,sys:user:list,.... 53 | String authority = ""; 54 | 55 | if (redisUtil.hasKey("GrantedAuthority:" + sysUser.getUsername())) { 56 | authority = (String) redisUtil.get("GrantedAuthority:" + sysUser.getUsername()); 57 | 58 | } else { 59 | // 获取角色编码 60 | List roles = sysRoleService.list(new QueryWrapper() 61 | .inSql("id", "select role_id from sys_user_role where user_id = " + userId)); 62 | 63 | if (roles.size() > 0) { 64 | String roleCodes = roles.stream().map(r -> "ROLE_" + r.getCode()).collect(Collectors.joining(",")); 65 | authority = roleCodes.concat(","); 66 | } 67 | 68 | // 获取菜单操作编码 69 | List menuIds = sysUserMapper.getNavMenuIds(userId); 70 | if (menuIds.size() > 0) { 71 | 72 | List menus = sysMenuService.listByIds(menuIds); 73 | String menuPerms = menus.stream().map(m -> m.getPerms()).collect(Collectors.joining(",")); 74 | 75 | authority = authority.concat(menuPerms); 76 | } 77 | 78 | redisUtil.set("GrantedAuthority:" + sysUser.getUsername(), authority, 60 * 60); 79 | } 80 | 81 | return authority; 82 | } 83 | 84 | @Override 85 | public void clearUserAuthorityInfo(String username) { 86 | redisUtil.del("GrantedAuthority:" + username); 87 | } 88 | 89 | @Override 90 | public void clearUserAuthorityInfoByRoleId(Long roleId) { 91 | 92 | List sysUsers = this.list(new QueryWrapper() 93 | .inSql("id", "select user_id from sys_user_role where role_id = " + roleId)); 94 | 95 | sysUsers.forEach(u -> { 96 | this.clearUserAuthorityInfo(u.getUsername()); 97 | }); 98 | 99 | } 100 | 101 | @Override 102 | public void clearUserAuthorityInfoByMenuId(Long menuId) { 103 | List sysUsers = sysUserMapper.listByMenuId(menuId); 104 | 105 | sysUsers.forEach(u -> { 106 | this.clearUserAuthorityInfo(u.getUsername()); 107 | }); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/controller/SysMenuController.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.controller; 2 | 3 | 4 | import cn.hutool.core.map.MapUtil; 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 | import com.markerhub.common.dto.SysMenuDto; 7 | import com.markerhub.common.lang.Const; 8 | import com.markerhub.common.lang.Result; 9 | import com.markerhub.entity.SysMenu; 10 | import com.markerhub.entity.SysRoleMenu; 11 | import com.markerhub.entity.SysUser; 12 | import org.apache.ibatis.executor.ResultExtractor; 13 | import org.springframework.security.access.prepost.PreAuthorize; 14 | import org.springframework.util.StringUtils; 15 | import org.springframework.validation.annotation.Validated; 16 | import org.springframework.web.bind.annotation.*; 17 | 18 | import java.security.Principal; 19 | import java.time.LocalDateTime; 20 | import java.util.List; 21 | 22 | /** 23 | *

24 | * 前端控制器 25 | *

26 | * 27 | * @author 我的公众号:MarkerHub 28 | * @since 2021-04-05 29 | */ 30 | @RestController 31 | @RequestMapping("/sys/menu") 32 | public class SysMenuController extends BaseController { 33 | 34 | /** 35 | * 用户当前用户的菜单和权限信息 36 | * @param principal 37 | * @return 38 | */ 39 | @GetMapping("/nav") 40 | public Result nav(Principal principal) { 41 | SysUser sysUser = sysUserService.getByUsername(principal.getName()); 42 | 43 | // 获取权限信息 44 | String authorityInfo = sysUserService.getUserAuthorityInfo(sysUser.getId());// ROLE_admin,ROLE_normal,sys:user:list,.... 45 | String[] authorityInfoArray = StringUtils.tokenizeToStringArray(authorityInfo, ","); 46 | 47 | // 获取导航栏信息 48 | List navs = sysMenuService.getCurrentUserNav(); 49 | 50 | return Result.succ(MapUtil.builder() 51 | .put("authoritys", authorityInfoArray) 52 | .put("nav", navs) 53 | .map() 54 | ); 55 | } 56 | 57 | @GetMapping("/info/{id}") 58 | @PreAuthorize("hasAuthority('sys:menu:list')") 59 | public Result info(@PathVariable(name = "id") Long id) { 60 | return Result.succ(sysMenuService.getById(id)); 61 | } 62 | 63 | @GetMapping("/list") 64 | @PreAuthorize("hasAuthority('sys:menu:list')") 65 | public Result list() { 66 | 67 | List menus = sysMenuService.tree(); 68 | return Result.succ(menus); 69 | } 70 | 71 | @PostMapping("/save") 72 | @PreAuthorize("hasAuthority('sys:menu:save')") 73 | public Result save(@Validated @RequestBody SysMenu sysMenu) { 74 | 75 | sysMenu.setCreated(LocalDateTime.now()); 76 | 77 | sysMenuService.save(sysMenu); 78 | return Result.succ(sysMenu); 79 | } 80 | 81 | @PostMapping("/update") 82 | @PreAuthorize("hasAuthority('sys:menu:update')") 83 | public Result update(@Validated @RequestBody SysMenu sysMenu) { 84 | 85 | sysMenu.setUpdated(LocalDateTime.now()); 86 | 87 | sysMenuService.updateById(sysMenu); 88 | 89 | // 清除所有与该菜单相关的权限缓存 90 | sysUserService.clearUserAuthorityInfoByMenuId(sysMenu.getId()); 91 | return Result.succ(sysMenu); 92 | } 93 | 94 | @PostMapping("/delete/{id}") 95 | @PreAuthorize("hasAuthority('sys:menu:delete')") 96 | public Result delete(@PathVariable("id") Long id) { 97 | 98 | int count = sysMenuService.count(new QueryWrapper().eq("parent_id", id)); 99 | if (count > 0) { 100 | return Result.fail("请先删除子菜单"); 101 | } 102 | 103 | // 清除所有与该菜单相关的权限缓存 104 | sysUserService.clearUserAuthorityInfoByMenuId(id); 105 | 106 | sysMenuService.removeById(id); 107 | 108 | // 同步删除中间关联表 109 | sysRoleMenuService.remove(new QueryWrapper().eq("menu_id", id)); 110 | return Result.succ(""); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /vueadmin-vue/src/views/Login.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 107 | 108 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/controller/SysRoleController.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.controller; 2 | 3 | 4 | import cn.hutool.core.util.StrUtil; 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 7 | import com.markerhub.common.lang.Const; 8 | import com.markerhub.common.lang.Result; 9 | import com.markerhub.entity.SysRole; 10 | import com.markerhub.entity.SysRoleMenu; 11 | import com.markerhub.entity.SysUserRole; 12 | import org.springframework.security.access.prepost.PreAuthorize; 13 | import org.springframework.transaction.annotation.Transactional; 14 | import org.springframework.validation.annotation.Validated; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | import java.time.LocalDateTime; 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.List; 21 | import java.util.stream.Collectors; 22 | 23 | /** 24 | *

25 | * 前端控制器 26 | * swagger2 27 | *

28 | * 29 | * @author 我的公众号:MarkerHub 30 | * @since 2021-04-05 31 | */ 32 | @RestController 33 | @RequestMapping("/sys/role") 34 | public class SysRoleController extends BaseController { 35 | 36 | @PreAuthorize("hasAuthority('sys:role:list')") 37 | @GetMapping("/info/{id}") 38 | public Result info(@PathVariable("id") Long id) { 39 | 40 | SysRole sysRole = sysRoleService.getById(id); 41 | 42 | // 获取角色相关联的菜单id 43 | List roleMenus = sysRoleMenuService.list(new QueryWrapper().eq("role_id", id)); 44 | List menuIds = roleMenus.stream().map(p -> p.getMenuId()).collect(Collectors.toList()); 45 | 46 | sysRole.setMenuIds(menuIds); 47 | return Result.succ(sysRole); 48 | } 49 | 50 | @PreAuthorize("hasAuthority('sys:role:list')") 51 | @GetMapping("/list") 52 | public Result list(String name) { 53 | 54 | Page pageData = sysRoleService.page(getPage(), 55 | new QueryWrapper() 56 | .like(StrUtil.isNotBlank(name), "name", name) 57 | ); 58 | 59 | return Result.succ(pageData); 60 | } 61 | 62 | @PostMapping("/save") 63 | @PreAuthorize("hasAuthority('sys:role:save')") 64 | public Result save(@Validated @RequestBody SysRole sysRole) { 65 | 66 | sysRole.setCreated(LocalDateTime.now()); 67 | sysRole.setStatu(Const.STATUS_ON); 68 | 69 | sysRoleService.save(sysRole); 70 | return Result.succ(sysRole); 71 | } 72 | 73 | @PostMapping("/update") 74 | @PreAuthorize("hasAuthority('sys:role:update')") 75 | public Result update(@Validated @RequestBody SysRole sysRole) { 76 | 77 | sysRole.setUpdated(LocalDateTime.now()); 78 | 79 | sysRoleService.updateById(sysRole); 80 | 81 | // 更新缓存 82 | sysUserService.clearUserAuthorityInfoByRoleId(sysRole.getId()); 83 | 84 | return Result.succ(sysRole); 85 | } 86 | 87 | @PostMapping("/delete") 88 | @PreAuthorize("hasAuthority('sys:role:delete')") 89 | @Transactional 90 | public Result info(@RequestBody Long[] ids) { 91 | 92 | sysRoleService.removeByIds(Arrays.asList(ids)); 93 | 94 | // 删除中间表 95 | sysUserRoleService.remove(new QueryWrapper().in("role_id", ids)); 96 | sysRoleMenuService.remove(new QueryWrapper().in("role_id", ids)); 97 | 98 | // 缓存同步删除 99 | Arrays.stream(ids).forEach(id -> { 100 | // 更新缓存 101 | sysUserService.clearUserAuthorityInfoByRoleId(id); 102 | }); 103 | 104 | return Result.succ(""); 105 | } 106 | 107 | @Transactional 108 | @PostMapping("/perm/{roleId}") 109 | @PreAuthorize("hasAuthority('sys:role:perm')") 110 | public Result info(@PathVariable("roleId") Long roleId, @RequestBody Long[] menuIds) { 111 | 112 | List sysRoleMenus = new ArrayList<>(); 113 | 114 | Arrays.stream(menuIds).forEach(menuId -> { 115 | SysRoleMenu roleMenu = new SysRoleMenu(); 116 | roleMenu.setMenuId(menuId); 117 | roleMenu.setRoleId(roleId); 118 | 119 | sysRoleMenus.add(roleMenu); 120 | }); 121 | 122 | // 先删除原来的记录,再保存新的 123 | sysRoleMenuService.remove(new QueryWrapper().eq("role_id", roleId)); 124 | sysRoleMenuService.saveBatch(sysRoleMenus); 125 | 126 | // 删除缓存 127 | sysUserService.clearUserAuthorityInfoByRoleId(roleId); 128 | 129 | return Result.succ(menuIds); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /vueadmin-java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.0 9 | 10 | 11 | com.markerhub 12 | vueadmin-java 13 | 0.0.1-SNAPSHOT 14 | vueadmin-java 15 | Demo project for Spring Boot 16 | 17 | 1.8 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-devtools 28 | runtime 29 | true 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | true 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | 43 | 44 | com.baomidou 45 | mybatis-plus-boot-starter 46 | 3.4.1 47 | 48 | 49 | 50 | com.baomidou 51 | mybatis-plus-generator 52 | 3.4.1 53 | 54 | 55 | org.freemarker 56 | freemarker 57 | 2.3.30 58 | 59 | 60 | mysql 61 | mysql-connector-java 62 | runtime 63 | 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-starter-security 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-starter-data-redis 73 | 74 | 75 | 76 | io.jsonwebtoken 77 | jjwt 78 | 0.9.1 79 | 80 | 81 | com.github.axet 82 | kaptcha 83 | 0.0.9 84 | 85 | 86 | 87 | cn.hutool 88 | hutool-all 89 | 5.3.3 90 | 91 | 92 | org.apache.commons 93 | commons-lang3 94 | 3.11 95 | 96 | 97 | 98 | org.springframework.boot 99 | spring-boot-starter-validation 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | org.springframework.boot 108 | spring-boot-maven-plugin 109 | 110 | 111 | 112 | org.projectlombok 113 | lombok 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/controller/SysUserController.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.controller; 2 | 3 | 4 | import cn.hutool.core.util.StrUtil; 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 7 | import com.markerhub.common.dto.PassDto; 8 | import com.markerhub.common.lang.Const; 9 | import com.markerhub.common.lang.Result; 10 | import com.markerhub.entity.SysRole; 11 | import com.markerhub.entity.SysUser; 12 | import com.markerhub.entity.SysUserRole; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.security.access.prepost.PreAuthorize; 15 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 16 | import org.springframework.transaction.annotation.Transactional; 17 | import org.springframework.util.Assert; 18 | import org.springframework.validation.annotation.Validated; 19 | import org.springframework.web.bind.annotation.*; 20 | 21 | import java.security.Principal; 22 | import java.time.LocalDateTime; 23 | import java.util.ArrayList; 24 | import java.util.Arrays; 25 | import java.util.List; 26 | 27 | /** 28 | *

29 | * 前端控制器 30 | *

31 | * 32 | * @author 我的公众号:MarkerHub 33 | * @since 2021-04-05 34 | */ 35 | @RestController 36 | @RequestMapping("/sys/user") 37 | public class SysUserController extends BaseController { 38 | 39 | @Autowired 40 | BCryptPasswordEncoder passwordEncoder; 41 | 42 | @GetMapping("/info/{id}") 43 | @PreAuthorize("hasAuthority('sys:user:list')") 44 | public Result info(@PathVariable("id") Long id) { 45 | 46 | SysUser sysUser = sysUserService.getById(id); 47 | Assert.notNull(sysUser, "找不到该管理员"); 48 | 49 | List roles = sysRoleService.listRolesByUserId(id); 50 | 51 | sysUser.setSysRoles(roles); 52 | return Result.succ(sysUser); 53 | } 54 | 55 | @GetMapping("/list") 56 | @PreAuthorize("hasAuthority('sys:user:list')") 57 | public Result list(String username) { 58 | 59 | Page pageData = sysUserService.page(getPage(), new QueryWrapper() 60 | .like(StrUtil.isNotBlank(username), "username", username)); 61 | 62 | pageData.getRecords().forEach(u -> { 63 | 64 | u.setSysRoles(sysRoleService.listRolesByUserId(u.getId())); 65 | }); 66 | 67 | return Result.succ(pageData); 68 | } 69 | 70 | @PostMapping("/save") 71 | @PreAuthorize("hasAuthority('sys:user:save')") 72 | public Result save(@Validated @RequestBody SysUser sysUser) { 73 | 74 | sysUser.setCreated(LocalDateTime.now()); 75 | sysUser.setStatu(Const.STATUS_ON); 76 | 77 | // 默认密码 78 | String password = passwordEncoder.encode(Const.DEFULT_PASSWORD); 79 | sysUser.setPassword(password); 80 | 81 | // 默认头像 82 | sysUser.setAvatar(Const.DEFULT_AVATAR); 83 | 84 | sysUserService.save(sysUser); 85 | return Result.succ(sysUser); 86 | } 87 | 88 | @PostMapping("/update") 89 | @PreAuthorize("hasAuthority('sys:user:update')") 90 | public Result update(@Validated @RequestBody SysUser sysUser) { 91 | 92 | sysUser.setUpdated(LocalDateTime.now()); 93 | 94 | sysUserService.updateById(sysUser); 95 | return Result.succ(sysUser); 96 | } 97 | 98 | @Transactional 99 | @PostMapping("/delete") 100 | @PreAuthorize("hasAuthority('sys:user:delete')") 101 | public Result delete(@RequestBody Long[] ids) { 102 | 103 | sysUserService.removeByIds(Arrays.asList(ids)); 104 | sysUserRoleService.remove(new QueryWrapper().in("user_id", ids)); 105 | 106 | return Result.succ(""); 107 | } 108 | 109 | @Transactional 110 | @PostMapping("/role/{userId}") 111 | @PreAuthorize("hasAuthority('sys:user:role')") 112 | public Result rolePerm(@PathVariable("userId") Long userId, @RequestBody Long[] roleIds) { 113 | 114 | List userRoles = new ArrayList<>(); 115 | 116 | Arrays.stream(roleIds).forEach(r -> { 117 | SysUserRole sysUserRole = new SysUserRole(); 118 | sysUserRole.setRoleId(r); 119 | sysUserRole.setUserId(userId); 120 | 121 | userRoles.add(sysUserRole); 122 | }); 123 | 124 | sysUserRoleService.remove(new QueryWrapper().eq("user_id", userId)); 125 | sysUserRoleService.saveBatch(userRoles); 126 | 127 | // 删除缓存 128 | SysUser sysUser = sysUserService.getById(userId); 129 | sysUserService.clearUserAuthorityInfo(sysUser.getUsername()); 130 | 131 | return Result.succ(""); 132 | } 133 | 134 | @PostMapping("/repass") 135 | @PreAuthorize("hasAuthority('sys:user:repass')") 136 | public Result repass(@RequestBody Long userId) { 137 | 138 | SysUser sysUser = sysUserService.getById(userId); 139 | 140 | sysUser.setPassword(passwordEncoder.encode(Const.DEFULT_PASSWORD)); 141 | sysUser.setUpdated(LocalDateTime.now()); 142 | 143 | sysUserService.updateById(sysUser); 144 | return Result.succ(""); 145 | } 146 | 147 | @PostMapping("/updatePass") 148 | public Result updatePass(@Validated @RequestBody PassDto passDto, Principal principal) { 149 | 150 | SysUser sysUser = sysUserService.getByUsername(principal.getName()); 151 | 152 | boolean matches = passwordEncoder.matches(passDto.getCurrentPass(), sysUser.getPassword()); 153 | if (!matches) { 154 | return Result.fail("旧密码不正确"); 155 | } 156 | 157 | sysUser.setPassword(passwordEncoder.encode(passDto.getPassword())); 158 | sysUser.setUpdated(LocalDateTime.now()); 159 | 160 | sysUserService.updateById(sysUser); 161 | return Result.succ(""); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/CodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.markerhub; 2 | 3 | import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; 4 | import com.baomidou.mybatisplus.core.toolkit.StringPool; 5 | import com.baomidou.mybatisplus.core.toolkit.StringUtils; 6 | import com.baomidou.mybatisplus.generator.AutoGenerator; 7 | import com.baomidou.mybatisplus.generator.InjectionConfig; 8 | import com.baomidou.mybatisplus.generator.config.*; 9 | import com.baomidou.mybatisplus.generator.config.po.TableInfo; 10 | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; 11 | import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Scanner; 16 | 17 | // 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 18 | public class CodeGenerator { 19 | 20 | /** 21 | *

22 | * 读取控制台内容 23 | *

24 | */ 25 | public static String scanner(String tip) { 26 | Scanner scanner = new Scanner(System.in); 27 | StringBuilder help = new StringBuilder(); 28 | help.append("请输入" + tip + ":"); 29 | System.out.println(help.toString()); 30 | if (scanner.hasNext()) { 31 | String ipt = scanner.next(); 32 | if (StringUtils.isNotBlank(ipt)) { 33 | return ipt; 34 | } 35 | } 36 | throw new MybatisPlusException("请输入正确的" + tip + "!"); 37 | } 38 | 39 | public static void main(String[] args) { 40 | // 代码生成器 41 | AutoGenerator mpg = new AutoGenerator(); 42 | 43 | // 全局配置 44 | GlobalConfig gc = new GlobalConfig(); 45 | String projectPath = System.getProperty("user.dir"); 46 | gc.setOutputDir(projectPath + "/src/main/java"); 47 | gc.setAuthor("我的公众号:MarkerHub"); 48 | gc.setOpen(false); 49 | // gc.setSwagger2(true); 实体属性 Swagger2 注解 50 | gc.setServiceName("%sService"); 51 | mpg.setGlobalConfig(gc); 52 | 53 | // 数据源配置 54 | DataSourceConfig dsc = new DataSourceConfig(); 55 | dsc.setUrl("jdbc:mysql://localhost:3306/vueadmin?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai"); 56 | // dsc.setSchemaName("public"); 57 | dsc.setDriverName("com.mysql.cj.jdbc.Driver"); 58 | dsc.setUsername("root"); 59 | dsc.setPassword("admin"); 60 | mpg.setDataSource(dsc); 61 | 62 | // 包配置 63 | PackageConfig pc = new PackageConfig(); 64 | // pc.setModuleName(scanner("模块名")); 65 | pc.setParent("com.markerhub"); 66 | mpg.setPackageInfo(pc); 67 | 68 | // 自定义配置 69 | InjectionConfig cfg = new InjectionConfig() { 70 | @Override 71 | public void initMap() { 72 | // to do nothing 73 | } 74 | }; 75 | 76 | // 如果模板引擎是 freemarker 77 | String templatePath = "/templates/mapper.xml.ftl"; 78 | // 如果模板引擎是 velocity 79 | // String templatePath = "/templates/mapper.xml.vm"; 80 | 81 | // 自定义输出配置 82 | List focList = new ArrayList<>(); 83 | // 自定义配置会被优先输出 84 | focList.add(new FileOutConfig(templatePath) { 85 | @Override 86 | public String outputFile(TableInfo tableInfo) { 87 | // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! 88 | return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() 89 | + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; 90 | } 91 | }); 92 | /* 93 | cfg.setFileCreate(new IFileCreate() { 94 | @Override 95 | public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) { 96 | // 判断自定义文件夹是否需要创建 97 | checkDir("调用默认方法创建的目录,自定义目录用"); 98 | if (fileType == FileType.MAPPER) { 99 | // 已经生成 mapper 文件判断存在,不想重新生成返回 false 100 | return !new File(filePath).exists(); 101 | } 102 | // 允许生成模板文件 103 | return true; 104 | } 105 | }); 106 | */ 107 | cfg.setFileOutConfigList(focList); 108 | mpg.setCfg(cfg); 109 | 110 | // 配置模板 111 | TemplateConfig templateConfig = new TemplateConfig(); 112 | 113 | // 配置自定义输出模板 114 | //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别 115 | // templateConfig.setEntity("templates/entity2.java"); 116 | // templateConfig.setService(); 117 | // templateConfig.setController(); 118 | 119 | templateConfig.setXml(null); 120 | mpg.setTemplate(templateConfig); 121 | 122 | // 策略配置 123 | StrategyConfig strategy = new StrategyConfig(); 124 | strategy.setNaming(NamingStrategy.underline_to_camel); 125 | strategy.setColumnNaming(NamingStrategy.underline_to_camel); 126 | strategy.setSuperEntityClass("BaseEntity"); 127 | strategy.setEntityLombokModel(true); 128 | strategy.setRestControllerStyle(true); 129 | // 公共父类 130 | strategy.setSuperControllerClass("BaseController"); 131 | // 写于父类中的公共字段 132 | strategy.setSuperEntityColumns("id", "created", "updated", "statu"); 133 | strategy.setInclude(scanner("表名,多个英文逗号分割").split(",")); 134 | strategy.setControllerMappingHyphenStyle(true); 135 | // strategy.setTablePrefix("sys_");//动态调整 136 | mpg.setStrategy(strategy); 137 | mpg.setTemplateEngine(new FreemarkerTemplateEngine()); 138 | mpg.execute(); 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /vueadmin-vue/src/views/sys/Menu.vue: -------------------------------------------------------------------------------- 1 | 162 | 163 | 258 | 259 | -------------------------------------------------------------------------------- /vueadmin-java/数据库脚本 - vueadmin.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : pro-markerhub 5 | Source Server Version : 50727 6 | Source Host : 129.204.23.53:3306 7 | Source Database : vueadmin 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50727 11 | File Encoding : 65001 12 | 13 | Date: 2021-01-30 21:02:31 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for sys_menu 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `sys_menu`; 22 | CREATE TABLE `sys_menu` ( 23 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 24 | `parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0', 25 | `name` varchar(64) NOT NULL, 26 | `path` varchar(255) DEFAULT NULL COMMENT '菜单URL', 27 | `perms` varchar(255) DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)', 28 | `component` varchar(255) DEFAULT NULL, 29 | `type` int(5) NOT NULL COMMENT '类型 0:目录 1:菜单 2:按钮', 30 | `icon` varchar(32) DEFAULT NULL COMMENT '菜单图标', 31 | `orderNum` int(11) DEFAULT NULL COMMENT '排序', 32 | `created` datetime NOT NULL, 33 | `updated` datetime DEFAULT NULL, 34 | `statu` int(5) NOT NULL, 35 | PRIMARY KEY (`id`), 36 | UNIQUE KEY `name` (`name`) USING BTREE 37 | ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8; 38 | 39 | -- ---------------------------- 40 | -- Records of sys_menu 41 | -- ---------------------------- 42 | INSERT INTO `sys_menu` VALUES ('1', '0', '系统管理', '', 'sys:manage', '', '0', 'el-icon-s-operation', '1', '2021-01-15 18:58:18', '2021-01-15 18:58:20', '1'); 43 | INSERT INTO `sys_menu` VALUES ('2', '1', '用户管理', '/sys/users', 'sys:user:list', 'sys/User', '1', 'el-icon-s-custom', '1', '2021-01-15 19:03:45', '2021-01-15 19:03:48', '1'); 44 | INSERT INTO `sys_menu` VALUES ('3', '1', '角色管理', '/sys/roles', 'sys:role:list', 'sys/Role', '1', 'el-icon-rank', '2', '2021-01-15 19:03:45', '2021-01-15 19:03:48', '1'); 45 | INSERT INTO `sys_menu` VALUES ('4', '1', '菜单管理', '/sys/menus', 'sys:menu:list', 'sys/Menu', '1', 'el-icon-menu', '3', '2021-01-15 19:03:45', '2021-01-15 19:03:48', '1'); 46 | INSERT INTO `sys_menu` VALUES ('5', '0', '系统工具', '', 'sys:tools', null, '0', 'el-icon-s-tools', '2', '2021-01-15 19:06:11', null, '1'); 47 | INSERT INTO `sys_menu` VALUES ('6', '5', '数字字典', '/sys/dicts', 'sys:dict:list', 'sys/Dict', '1', 'el-icon-s-order', '1', '2021-01-15 19:07:18', '2021-01-18 16:32:13', '1'); 48 | INSERT INTO `sys_menu` VALUES ('7', '3', '添加角色', '', 'sys:role:save', '', '2', '', '1', '2021-01-15 23:02:25', '2021-01-17 21:53:14', '0'); 49 | INSERT INTO `sys_menu` VALUES ('9', '2', '添加用户', null, 'sys:user:save', null, '2', null, '1', '2021-01-17 21:48:32', null, '1'); 50 | INSERT INTO `sys_menu` VALUES ('10', '2', '修改用户', null, 'sys:user:update', null, '2', null, '2', '2021-01-17 21:49:03', '2021-01-17 21:53:04', '1'); 51 | INSERT INTO `sys_menu` VALUES ('11', '2', '删除用户', null, 'sys:user:delete', null, '2', null, '3', '2021-01-17 21:49:21', null, '1'); 52 | INSERT INTO `sys_menu` VALUES ('12', '2', '分配角色', null, 'sys:user:role', null, '2', null, '4', '2021-01-17 21:49:58', null, '1'); 53 | INSERT INTO `sys_menu` VALUES ('13', '2', '重置密码', null, 'sys:user:repass', null, '2', null, '5', '2021-01-17 21:50:36', null, '1'); 54 | INSERT INTO `sys_menu` VALUES ('14', '3', '修改角色', null, 'sys:role:update', null, '2', null, '2', '2021-01-17 21:51:14', null, '1'); 55 | INSERT INTO `sys_menu` VALUES ('15', '3', '删除角色', null, 'sys:role:delete', null, '2', null, '3', '2021-01-17 21:51:39', null, '1'); 56 | INSERT INTO `sys_menu` VALUES ('16', '3', '分配权限', null, 'sys:role:perm', null, '2', null, '5', '2021-01-17 21:52:02', null, '1'); 57 | INSERT INTO `sys_menu` VALUES ('17', '4', '添加菜单', null, 'sys:menu:save', null, '2', null, '1', '2021-01-17 21:53:53', '2021-01-17 21:55:28', '1'); 58 | INSERT INTO `sys_menu` VALUES ('18', '4', '修改菜单', null, 'sys:menu:update', null, '2', null, '2', '2021-01-17 21:56:12', null, '1'); 59 | INSERT INTO `sys_menu` VALUES ('19', '4', '删除菜单', null, 'sys:menu:delete', null, '2', null, '3', '2021-01-17 21:56:36', null, '1'); 60 | 61 | -- ---------------------------- 62 | -- Table structure for sys_role 63 | -- ---------------------------- 64 | DROP TABLE IF EXISTS `sys_role`; 65 | CREATE TABLE `sys_role` ( 66 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 67 | `name` varchar(64) NOT NULL, 68 | `code` varchar(64) NOT NULL, 69 | `remark` varchar(64) DEFAULT NULL COMMENT '备注', 70 | `created` datetime DEFAULT NULL, 71 | `updated` datetime DEFAULT NULL, 72 | `statu` int(5) NOT NULL, 73 | PRIMARY KEY (`id`), 74 | UNIQUE KEY `name` (`name`) USING BTREE, 75 | UNIQUE KEY `code` (`code`) USING BTREE 76 | ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; 77 | 78 | -- ---------------------------- 79 | -- Records of sys_role 80 | -- ---------------------------- 81 | INSERT INTO `sys_role` VALUES ('3', '普通用户', 'normal', '只有基本查看功能', '2021-01-04 10:09:14', '2021-01-30 08:19:52', '1'); 82 | INSERT INTO `sys_role` VALUES ('6', '超级管理员', 'admin', '系统默认最高权限,不可以编辑和任意修改', '2021-01-16 13:29:03', '2021-01-17 15:50:45', '1'); 83 | 84 | -- ---------------------------- 85 | -- Table structure for sys_role_menu 86 | -- ---------------------------- 87 | DROP TABLE IF EXISTS `sys_role_menu`; 88 | CREATE TABLE `sys_role_menu` ( 89 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 90 | `role_id` bigint(20) NOT NULL, 91 | `menu_id` bigint(20) NOT NULL, 92 | PRIMARY KEY (`id`) 93 | ) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8mb4; 94 | 95 | -- ---------------------------- 96 | -- Records of sys_role_menu 97 | -- ---------------------------- 98 | INSERT INTO `sys_role_menu` VALUES ('60', '6', '1'); 99 | INSERT INTO `sys_role_menu` VALUES ('61', '6', '2'); 100 | INSERT INTO `sys_role_menu` VALUES ('62', '6', '9'); 101 | INSERT INTO `sys_role_menu` VALUES ('63', '6', '10'); 102 | INSERT INTO `sys_role_menu` VALUES ('64', '6', '11'); 103 | INSERT INTO `sys_role_menu` VALUES ('65', '6', '12'); 104 | INSERT INTO `sys_role_menu` VALUES ('66', '6', '13'); 105 | INSERT INTO `sys_role_menu` VALUES ('67', '6', '3'); 106 | INSERT INTO `sys_role_menu` VALUES ('68', '6', '7'); 107 | INSERT INTO `sys_role_menu` VALUES ('69', '6', '14'); 108 | INSERT INTO `sys_role_menu` VALUES ('70', '6', '15'); 109 | INSERT INTO `sys_role_menu` VALUES ('71', '6', '16'); 110 | INSERT INTO `sys_role_menu` VALUES ('72', '6', '4'); 111 | INSERT INTO `sys_role_menu` VALUES ('73', '6', '17'); 112 | INSERT INTO `sys_role_menu` VALUES ('74', '6', '18'); 113 | INSERT INTO `sys_role_menu` VALUES ('75', '6', '19'); 114 | INSERT INTO `sys_role_menu` VALUES ('76', '6', '5'); 115 | INSERT INTO `sys_role_menu` VALUES ('77', '6', '6'); 116 | INSERT INTO `sys_role_menu` VALUES ('96', '3', '1'); 117 | INSERT INTO `sys_role_menu` VALUES ('97', '3', '2'); 118 | INSERT INTO `sys_role_menu` VALUES ('98', '3', '3'); 119 | INSERT INTO `sys_role_menu` VALUES ('99', '3', '4'); 120 | INSERT INTO `sys_role_menu` VALUES ('100', '3', '5'); 121 | INSERT INTO `sys_role_menu` VALUES ('101', '3', '6'); 122 | 123 | -- ---------------------------- 124 | -- Table structure for sys_user 125 | -- ---------------------------- 126 | DROP TABLE IF EXISTS `sys_user`; 127 | CREATE TABLE `sys_user` ( 128 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 129 | `username` varchar(64) DEFAULT NULL, 130 | `password` varchar(64) DEFAULT NULL, 131 | `avatar` varchar(255) DEFAULT NULL, 132 | `email` varchar(64) DEFAULT NULL, 133 | `city` varchar(64) DEFAULT NULL, 134 | `created` datetime DEFAULT NULL, 135 | `updated` datetime DEFAULT NULL, 136 | `last_login` datetime DEFAULT NULL, 137 | `statu` int(5) NOT NULL, 138 | PRIMARY KEY (`id`), 139 | UNIQUE KEY `UK_USERNAME` (`username`) USING BTREE 140 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 141 | 142 | -- ---------------------------- 143 | -- Records of sys_user 144 | -- ---------------------------- 145 | INSERT INTO `sys_user` VALUES ('1', 'admin', '$2a$10$R7zegeWzOXPw871CmNuJ6upC0v8D373GuLuTw8jn6NET4BkPRZfgK', 'https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg', '123@qq.com', '广州', '2021-01-12 22:13:53', '2021-01-16 16:57:32', '2020-12-30 08:38:37', '1'); 146 | INSERT INTO `sys_user` VALUES ('2', 'test', '$2a$10$0ilP4ZD1kLugYwLCs4pmb.ZT9cFqzOZTNaMiHxrBnVIQUGUwEvBIO', 'https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg', 'test@qq.com', null, '2021-01-30 08:20:22', '2021-01-30 08:55:57', null, '1'); 147 | 148 | -- ---------------------------- 149 | -- Table structure for sys_user_role 150 | -- ---------------------------- 151 | DROP TABLE IF EXISTS `sys_user_role`; 152 | CREATE TABLE `sys_user_role` ( 153 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 154 | `user_id` bigint(20) NOT NULL, 155 | `role_id` bigint(20) NOT NULL, 156 | PRIMARY KEY (`id`) 157 | ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4; 158 | 159 | -- ---------------------------- 160 | -- Records of sys_user_role 161 | -- ---------------------------- 162 | INSERT INTO `sys_user_role` VALUES ('4', '1', '6'); 163 | INSERT INTO `sys_user_role` VALUES ('7', '1', '3'); 164 | INSERT INTO `sys_user_role` VALUES ('13', '2', '3'); 165 | -------------------------------------------------------------------------------- /vueadmin-vue/src/views/sys/Role.vue: -------------------------------------------------------------------------------- 1 | 165 | 166 | 355 | 356 | -------------------------------------------------------------------------------- /vueadmin-vue/src/views/sys/User.vue: -------------------------------------------------------------------------------- 1 | 185 | 186 | 400 | 401 | -------------------------------------------------------------------------------- /vueadmin-vue/src/mock.js: -------------------------------------------------------------------------------- 1 | const Mock = require('mockjs') 2 | 3 | const Random = Mock.Random 4 | 5 | let Result = { 6 | code: 200, 7 | msg: '操作成功', 8 | data: null 9 | } 10 | 11 | Mock.mock('/captcha', 'get', () => { 12 | 13 | Result.data = { 14 | token: Random.string(32), 15 | captchaImg: Random.dataImage('120x40', 'p7n5w') 16 | } 17 | return Result 18 | }) 19 | 20 | Mock.mock('/login', 'post', () => { 21 | 22 | // 无法在header中传入数jwt 23 | 24 | // Result.code = 400 25 | // Result.msg = "验证码错误" 26 | 27 | return Result 28 | }) 29 | Mock.mock('/sys/userInfo', 'get', () => { 30 | 31 | Result.data = { 32 | id: "1", 33 | username: "test", 34 | avatar: "https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg" 35 | } 36 | 37 | return Result 38 | }) 39 | 40 | Mock.mock('/logout', 'post', () => { 41 | 42 | return Result 43 | }) 44 | 45 | // 获取用户菜单以及权限接口 46 | Mock.mock('/sys/menu/nav', 'get', () => { 47 | 48 | let nav = [ 49 | { 50 | name: 'SysManga', 51 | title: '系统管理', 52 | icon: 'el-icon-s-operation', 53 | component: '', 54 | path: '', 55 | children: [ 56 | { 57 | name: 'SysUser', 58 | title: '用户管理', 59 | icon: 'el-icon-s-custom', 60 | path: '/sys/users', 61 | component: 'sys/User', 62 | children: [] 63 | }, 64 | { 65 | name: 'SysRole', 66 | title: '角色管理', 67 | icon: 'el-icon-rank', 68 | path: '/sys/roles', 69 | component: 'sys/Role', 70 | children: [] 71 | }, 72 | { 73 | name: 'SysMenu', 74 | title: '菜单管理', 75 | icon: 'el-icon-menu', 76 | path: '/sys/menus', 77 | component: 'sys/Menu', 78 | children: [] 79 | } 80 | ] 81 | }, 82 | { 83 | name: 'SysTools', 84 | title: '系统工具', 85 | icon: 'el-icon-s-tools', 86 | path: '', 87 | component: '', 88 | children: [ 89 | { 90 | name: 'SysDict', 91 | title: '数字字典', 92 | icon: 'el-icon-s-order', 93 | path: '/sys/dicts', 94 | component: '', 95 | children: [] 96 | }, 97 | ] 98 | } 99 | ] 100 | 101 | let authoritys = ['sys:user:list', "sys:user:save", "sys:user:delete"] 102 | 103 | Result.data = { 104 | nav: nav, 105 | authoritys: authoritys 106 | } 107 | 108 | return Result 109 | }) 110 | 111 | //////////////// 菜单管理 //////////////// 112 | 113 | Mock.mock('/sys/menu/list', 'get', () => { 114 | let menus = [ 115 | { 116 | "id": 1, 117 | "created": "2021-01-15T18:58:18", 118 | "updated": "2021-01-15T18:58:20", 119 | "statu": 1, 120 | "parentId": 0, 121 | "name": "系统管理", 122 | "path": "", 123 | "perms": "sys:manage", 124 | "component": "", 125 | "type": 0, 126 | "icon": "el-icon-s-operation", 127 | "ordernum": 1, 128 | "children": [ 129 | { 130 | "id": 2, 131 | "created": "2021-01-15T19:03:45", 132 | "updated": "2021-01-15T19:03:48", 133 | "statu": 1, 134 | "parentId": 1, 135 | "name": "用户管理", 136 | "path": "/sys/users", 137 | "perms": "sys:user:list", 138 | "component": "sys/User", 139 | "type": 1, 140 | "icon": "el-icon-s-custom", 141 | "ordernum": 1, 142 | "children": [ 143 | { 144 | "id": 9, 145 | "created": "2021-01-17T21:48:32", 146 | "updated": null, 147 | "statu": 1, 148 | "parentId": 2, 149 | "name": "添加用户", 150 | "path": null, 151 | "perms": "sys:user:save", 152 | "component": null, 153 | "type": 2, 154 | "icon": null, 155 | "ordernum": 1, 156 | "children": [] 157 | }, 158 | { 159 | "id": 10, 160 | "created": "2021-01-17T21:49:03", 161 | "updated": "2021-01-17T21:53:04", 162 | "statu": 1, 163 | "parentId": 2, 164 | "name": "修改用户", 165 | "path": null, 166 | "perms": "sys:user:update", 167 | "component": null, 168 | "type": 2, 169 | "icon": null, 170 | "ordernum": 2, 171 | "children": [] 172 | }, 173 | { 174 | "id": 11, 175 | "created": "2021-01-17T21:49:21", 176 | "updated": null, 177 | "statu": 1, 178 | "parentId": 2, 179 | "name": "删除用户", 180 | "path": null, 181 | "perms": "sys:user:delete", 182 | "component": null, 183 | "type": 2, 184 | "icon": null, 185 | "ordernum": 3, 186 | "children": [] 187 | }, 188 | { 189 | "id": 12, 190 | "created": "2021-01-17T21:49:58", 191 | "updated": null, 192 | "statu": 1, 193 | "parentId": 2, 194 | "name": "分配角色", 195 | "path": null, 196 | "perms": "sys:user:role", 197 | "component": null, 198 | "type": 2, 199 | "icon": null, 200 | "ordernum": 4, 201 | "children": [] 202 | }, 203 | { 204 | "id": 13, 205 | "created": "2021-01-17T21:50:36", 206 | "updated": null, 207 | "statu": 1, 208 | "parentId": 2, 209 | "name": "重置密码", 210 | "path": null, 211 | "perms": "sys:user:repass", 212 | "component": null, 213 | "type": 2, 214 | "icon": null, 215 | "ordernum": 5, 216 | "children": [] 217 | } 218 | ] 219 | }, 220 | { 221 | "id": 3, 222 | "created": "2021-01-15T19:03:45", 223 | "updated": "2021-01-15T19:03:48", 224 | "statu": 1, 225 | "parentId": 1, 226 | "name": "角色管理", 227 | "path": "/sys/roles", 228 | "perms": "sys:role:list", 229 | "component": "sys/Role", 230 | "type": 1, 231 | "icon": "el-icon-rank", 232 | "ordernum": 2, 233 | "children": [] 234 | }, 235 | 236 | ] 237 | }, 238 | { 239 | "id": 5, 240 | "created": "2021-01-15T19:06:11", 241 | "updated": null, 242 | "statu": 1, 243 | "parentId": 0, 244 | "name": "系统工具", 245 | "path": "", 246 | "perms": "sys:tools", 247 | "component": null, 248 | "type": 0, 249 | "icon": "el-icon-s-tools", 250 | "ordernum": 2, 251 | "children": [ 252 | { 253 | "id": 6, 254 | "created": "2021-01-15T19:07:18", 255 | "updated": "2021-01-18T16:32:13", 256 | "statu": 1, 257 | "parentId": 5, 258 | "name": "数字字典", 259 | "path": "/sys/dicts", 260 | "perms": "sys:dict:list", 261 | "component": "sys/Dict", 262 | "type": 1, 263 | "icon": "el-icon-s-order", 264 | "ordernum": 1, 265 | "children": [] 266 | } 267 | ] 268 | } 269 | ] 270 | 271 | Result.data = menus 272 | 273 | return Result 274 | }) 275 | 276 | Mock.mock(RegExp('/sys/menu/info/*'), 'get', () => { 277 | 278 | Result.data = { 279 | "id": 3, 280 | "statu": 1, 281 | "parentId": 1, 282 | "name": "角色管理", 283 | "path": "/sys/roles", 284 | "perms": "sys:role:list", 285 | "component": "sys/Role", 286 | "type": 1, 287 | "icon": "el-icon-rank", 288 | "orderNum": 2, 289 | "children": [] 290 | } 291 | 292 | return Result 293 | }) 294 | 295 | 296 | Mock.mock(RegExp('/sys/menu/*'), 'post', () => { 297 | 298 | return Result 299 | }) 300 | 301 | //////////////// 角色管理 //////////////// 302 | 303 | Mock.mock(RegExp('/sys/role/list*'), 'get', () => { 304 | 305 | Result.data = { 306 | "records": [ 307 | { 308 | "id": 3, 309 | "created": "2021-01-04T10:09:14", 310 | "updated": "2021-01-30T08:19:52", 311 | "statu": 1, 312 | "name": "普通用户", 313 | "code": "normal", 314 | "remark": "只有基本查看功能", 315 | "menuIds": [] 316 | }, 317 | { 318 | "id": 6, 319 | "created": "2021-01-16T13:29:03", 320 | "updated": "2021-01-17T15:50:45", 321 | "statu": 1, 322 | "name": "超级管理员", 323 | "code": "admin", 324 | "remark": "系统默认最高权限,不可以编辑和任意修改", 325 | "menuIds": [] 326 | } 327 | ], 328 | "total": 2, 329 | "size": 10, 330 | "current": 1, 331 | "orders": [], 332 | "optimizeCountSql": true, 333 | "hitCount": false, 334 | "countId": null, 335 | "maxLimit": null, 336 | "searchCount": true, 337 | "pages": 1 338 | } 339 | 340 | return Result 341 | 342 | }) 343 | 344 | Mock.mock(RegExp('/sys/role/info/*'), 'get', () => { 345 | 346 | Result.data = { 347 | "id": 6, 348 | "created": "2021-01-16T13:29:03", 349 | "updated": "2021-01-17T15:50:45", 350 | "statu": 1, 351 | "name": "超级管理员", 352 | "code": "admin", 353 | "remark": "系统默认最高权限,不可以编辑和任意修改", 354 | "menuIds": [3] 355 | } 356 | 357 | return Result 358 | }) 359 | 360 | Mock.mock(RegExp('/sys/role/*'), 'post', () => { 361 | 362 | return Result 363 | }) 364 | 365 | //////////////// 用户管理 //////////////// 366 | 367 | Mock.mock(RegExp('/sys/user/list*'), 'get', () => { 368 | Result.data = { 369 | "records": [ 370 | { 371 | "id": 1, 372 | "created": "2021-01-12T22:13:53", 373 | "updated": "2021-01-16T16:57:32", 374 | "statu": 1, 375 | "username": "admin", 376 | "password": "$2a$10$R7zegeWzOXPw871CmNuJ6upC0v8D373GuLuTw8jn6NET4BkPRZfgK", 377 | "avatar": "https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg", 378 | "email": "123@qq.com", 379 | "city": "广州", 380 | "lastLogin": "2020-12-30T08:38:37", 381 | "roles": [ 382 | { 383 | "id": 6, 384 | "created": "2021-01-16T13:29:03", 385 | "updated": "2021-01-17T15:50:45", 386 | "statu": 1, 387 | "name": "超级管理员", 388 | "code": "admin", 389 | "remark": "系统默认最高权限,不可以编辑和任意修改", 390 | "menuIds": [] 391 | }, 392 | { 393 | "id": 3, 394 | "created": "2021-01-04T10:09:14", 395 | "updated": "2021-01-30T08:19:52", 396 | "statu": 1, 397 | "name": "普通用户", 398 | "code": "normal", 399 | "remark": "只有基本查看功能", 400 | "menuIds": [] 401 | } 402 | ] 403 | }, 404 | { 405 | "id": 2, 406 | "created": "2021-01-30T08:20:22", 407 | "updated": "2021-01-30T08:55:57", 408 | "statu": 1, 409 | "username": "test", 410 | "password": "$2a$10$0ilP4ZD1kLugYwLCs4pmb.ZT9cFqzOZTNaMiHxrBnVIQUGUwEvBIO", 411 | "avatar": "https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg", 412 | "email": "test@qq.com", 413 | "city": null, 414 | "lastLogin": null, 415 | "roles": [ 416 | { 417 | "id": 3, 418 | "created": "2021-01-04T10:09:14", 419 | "updated": "2021-01-30T08:19:52", 420 | "statu": 1, 421 | "name": "普通用户", 422 | "code": "normal", 423 | "remark": "只有基本查看功能", 424 | "menuIds": [] 425 | } 426 | ] 427 | } 428 | ], 429 | "total": 2, 430 | "size": 10, 431 | "current": 1, 432 | "orders": [], 433 | "optimizeCountSql": true, 434 | "hitCount": false, 435 | "countId": null, 436 | "maxLimit": null, 437 | "searchCount": true, 438 | "pages": 1 439 | } 440 | 441 | return Result 442 | }) 443 | 444 | 445 | Mock.mock(RegExp('/sys/user/*'), 'post', () => { 446 | return Result 447 | }) 448 | 449 | Mock.mock(RegExp('/sys/user/info/*'), 'get', () => { 450 | 451 | Result.data = { 452 | "id": 2, 453 | "created": "2021-01-30T08:20:22", 454 | "updated": "2021-01-30T08:55:57", 455 | "statu": 1, 456 | "username": "test", 457 | "password": "$2a$10$0ilP4ZD1kLugYwLCs4pmb.ZT9cFqzOZTNaMiHxrBnVIQUGUwEvBIO", 458 | "avatar": "https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg", 459 | "email": "test@qq.com", 460 | "city": null, 461 | "lastLogin": null, 462 | "roles": [] 463 | } 464 | return Result 465 | }) -------------------------------------------------------------------------------- /vueadmin-java/src/main/java/com/markerhub/utils/RedisUtil.java: -------------------------------------------------------------------------------- 1 | package com.markerhub.utils; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.data.redis.core.RedisTemplate; 5 | import org.springframework.data.redis.core.ZSetOperations; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.util.CollectionUtils; 8 | 9 | import java.util.Collection; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Set; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | @Component 16 | public class RedisUtil { 17 | 18 | @Autowired 19 | private RedisTemplate redisTemplate; 20 | 21 | /** 22 | * 指定缓存失效时间 23 | * 24 | * @param key 键 25 | * @param time 时间(秒) 26 | * @return 27 | */ 28 | public boolean expire(String key, long time) { 29 | try { 30 | if (time > 0) { 31 | redisTemplate.expire(key, time, TimeUnit.SECONDS); 32 | } 33 | return true; 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | return false; 37 | } 38 | } 39 | 40 | /** 41 | * 根据key 获取过期时间 42 | * 43 | * @param key 键 不能为null 44 | * @return 时间(秒) 返回0代表为永久有效 45 | */ 46 | public long getExpire(String key) { 47 | return redisTemplate.getExpire(key, TimeUnit.SECONDS); 48 | } 49 | 50 | /** 51 | * 判断key是否存在 52 | * 53 | * @param key 键 54 | * @return true 存在 false不存在 55 | */ 56 | public boolean hasKey(String key) { 57 | try { 58 | return redisTemplate.hasKey(key); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | return false; 62 | } 63 | } 64 | 65 | /** 66 | * 删除缓存 67 | * 68 | * @param key 可以传一个值 或多个 69 | */ 70 | @SuppressWarnings("unchecked") 71 | public void del(String... key) { 72 | if (key != null && key.length > 0) { 73 | if (key.length == 1) { 74 | redisTemplate.delete(key[0]); 75 | } else { 76 | redisTemplate.delete(CollectionUtils.arrayToList(key)); 77 | } 78 | } 79 | } 80 | 81 | //============================String============================= 82 | 83 | /** 84 | * 普通缓存获取 85 | * 86 | * @param key 键 87 | * @return 值 88 | */ 89 | public Object get(String key) { 90 | return key == null ? null : redisTemplate.opsForValue().get(key); 91 | } 92 | 93 | /** 94 | * 普通缓存放入 95 | * 96 | * @param key 键 97 | * @param value 值 98 | * @return true成功 false失败 99 | */ 100 | public boolean set(String key, Object value) { 101 | try { 102 | redisTemplate.opsForValue().set(key, value); 103 | return true; 104 | } catch (Exception e) { 105 | e.printStackTrace(); 106 | return false; 107 | } 108 | 109 | } 110 | 111 | /** 112 | * 普通缓存放入并设置时间 113 | * 114 | * @param key 键 115 | * @param value 值 116 | * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 117 | * @return true成功 false 失败 118 | */ 119 | public boolean set(String key, Object value, long time) { 120 | try { 121 | if (time > 0) { 122 | redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); 123 | } else { 124 | set(key, value); 125 | } 126 | return true; 127 | } catch (Exception e) { 128 | e.printStackTrace(); 129 | return false; 130 | } 131 | } 132 | 133 | /** 134 | * 递增 135 | * 136 | * @param key 键 137 | * @param delta 要增加几(大于0) 138 | * @return 139 | */ 140 | public long incr(String key, long delta) { 141 | if (delta < 0) { 142 | throw new RuntimeException("递增因子必须大于0"); 143 | } 144 | return redisTemplate.opsForValue().increment(key, delta); 145 | } 146 | 147 | /** 148 | * 递减 149 | * 150 | * @param key 键 151 | * @param delta 要减少几(小于0) 152 | * @return 153 | */ 154 | public long decr(String key, long delta) { 155 | if (delta < 0) { 156 | throw new RuntimeException("递减因子必须大于0"); 157 | } 158 | return redisTemplate.opsForValue().increment(key, -delta); 159 | } 160 | 161 | //================================Map================================= 162 | 163 | /** 164 | * HashGet 165 | * 166 | * @param key 键 不能为null 167 | * @param item 项 不能为null 168 | * @return 值 169 | */ 170 | public Object hget(String key, String item) { 171 | return redisTemplate.opsForHash().get(key, item); 172 | } 173 | 174 | /** 175 | * 获取hashKey对应的所有键值 176 | * 177 | * @param key 键 178 | * @return 对应的多个键值 179 | */ 180 | public Map hmget(String key) { 181 | return redisTemplate.opsForHash().entries(key); 182 | } 183 | 184 | /** 185 | * HashSet 186 | * 187 | * @param key 键 188 | * @param map 对应多个键值 189 | * @return true 成功 false 失败 190 | */ 191 | public boolean hmset(String key, Map map) { 192 | try { 193 | redisTemplate.opsForHash().putAll(key, map); 194 | return true; 195 | } catch (Exception e) { 196 | e.printStackTrace(); 197 | return false; 198 | } 199 | } 200 | 201 | /** 202 | * HashSet 并设置时间 203 | * 204 | * @param key 键 205 | * @param map 对应多个键值 206 | * @param time 时间(秒) 207 | * @return true成功 false失败 208 | */ 209 | public boolean hmset(String key, Map map, long time) { 210 | try { 211 | redisTemplate.opsForHash().putAll(key, map); 212 | if (time > 0) { 213 | expire(key, time); 214 | } 215 | return true; 216 | } catch (Exception e) { 217 | e.printStackTrace(); 218 | return false; 219 | } 220 | } 221 | 222 | /** 223 | * 向一张hash表中放入数据,如果不存在将创建 224 | * 225 | * @param key 键 226 | * @param item 项 227 | * @param value 值 228 | * @return true 成功 false失败 229 | */ 230 | public boolean hset(String key, String item, Object value) { 231 | try { 232 | redisTemplate.opsForHash().put(key, item, value); 233 | return true; 234 | } catch (Exception e) { 235 | e.printStackTrace(); 236 | return false; 237 | } 238 | } 239 | 240 | /** 241 | * 向一张hash表中放入数据,如果不存在将创建 242 | * 243 | * @param key 键 244 | * @param item 项 245 | * @param value 值 246 | * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 247 | * @return true 成功 false失败 248 | */ 249 | public boolean hset(String key, String item, Object value, long time) { 250 | try { 251 | redisTemplate.opsForHash().put(key, item, value); 252 | if (time > 0) { 253 | expire(key, time); 254 | } 255 | return true; 256 | } catch (Exception e) { 257 | e.printStackTrace(); 258 | return false; 259 | } 260 | } 261 | 262 | /** 263 | * 删除hash表中的值 264 | * 265 | * @param key 键 不能为null 266 | * @param item 项 可以使多个 不能为null 267 | */ 268 | public void hdel(String key, Object... item) { 269 | redisTemplate.opsForHash().delete(key, item); 270 | } 271 | 272 | /** 273 | * 判断hash表中是否有该项的值 274 | * 275 | * @param key 键 不能为null 276 | * @param item 项 不能为null 277 | * @return true 存在 false不存在 278 | */ 279 | public boolean hHasKey(String key, String item) { 280 | return redisTemplate.opsForHash().hasKey(key, item); 281 | } 282 | 283 | /** 284 | * hash递增 如果不存在,就会创建一个 并把新增后的值返回 285 | * 286 | * @param key 键 287 | * @param item 项 288 | * @param by 要增加几(大于0) 289 | * @return 290 | */ 291 | public double hincr(String key, String item, double by) { 292 | return redisTemplate.opsForHash().increment(key, item, by); 293 | } 294 | 295 | /** 296 | * hash递减 297 | * 298 | * @param key 键 299 | * @param item 项 300 | * @param by 要减少记(小于0) 301 | * @return 302 | */ 303 | public double hdecr(String key, String item, double by) { 304 | return redisTemplate.opsForHash().increment(key, item, -by); 305 | } 306 | 307 | //============================set============================= 308 | 309 | /** 310 | * 根据key获取Set中的所有值 311 | * 312 | * @param key 键 313 | * @return 314 | */ 315 | public Set sGet(String key) { 316 | try { 317 | return redisTemplate.opsForSet().members(key); 318 | } catch (Exception e) { 319 | e.printStackTrace(); 320 | return null; 321 | } 322 | } 323 | 324 | /** 325 | * 根据value从一个set中查询,是否存在 326 | * 327 | * @param key 键 328 | * @param value 值 329 | * @return true 存在 false不存在 330 | */ 331 | public boolean sHasKey(String key, Object value) { 332 | try { 333 | return redisTemplate.opsForSet().isMember(key, value); 334 | } catch (Exception e) { 335 | e.printStackTrace(); 336 | return false; 337 | } 338 | } 339 | 340 | /** 341 | * 将数据放入set缓存 342 | * 343 | * @param key 键 344 | * @param values 值 可以是多个 345 | * @return 成功个数 346 | */ 347 | public long sSet(String key, Object... values) { 348 | try { 349 | return redisTemplate.opsForSet().add(key, values); 350 | } catch (Exception e) { 351 | e.printStackTrace(); 352 | return 0; 353 | } 354 | } 355 | 356 | /** 357 | * 将set数据放入缓存 358 | * 359 | * @param key 键 360 | * @param time 时间(秒) 361 | * @param values 值 可以是多个 362 | * @return 成功个数 363 | */ 364 | public long sSetAndTime(String key, long time, Object... values) { 365 | try { 366 | Long count = redisTemplate.opsForSet().add(key, values); 367 | if (time > 0) expire(key, time); 368 | return count; 369 | } catch (Exception e) { 370 | e.printStackTrace(); 371 | return 0; 372 | } 373 | } 374 | 375 | /** 376 | * 获取set缓存的长度 377 | * 378 | * @param key 键 379 | * @return 380 | */ 381 | public long sGetSetSize(String key) { 382 | try { 383 | return redisTemplate.opsForSet().size(key); 384 | } catch (Exception e) { 385 | e.printStackTrace(); 386 | return 0; 387 | } 388 | } 389 | 390 | /** 391 | * 移除值为value的 392 | * 393 | * @param key 键 394 | * @param values 值 可以是多个 395 | * @return 移除的个数 396 | */ 397 | public long setRemove(String key, Object... values) { 398 | try { 399 | Long count = redisTemplate.opsForSet().remove(key, values); 400 | return count; 401 | } catch (Exception e) { 402 | e.printStackTrace(); 403 | return 0; 404 | } 405 | } 406 | //===============================list================================= 407 | 408 | /** 409 | * 获取list缓存的内容 410 | * 411 | * @param key 键 412 | * @param start 开始 413 | * @param end 结束 0 到 -1代表所有值 414 | * @return 415 | */ 416 | public List lGet(String key, long start, long end) { 417 | try { 418 | return redisTemplate.opsForList().range(key, start, end); 419 | } catch (Exception e) { 420 | e.printStackTrace(); 421 | return null; 422 | } 423 | } 424 | 425 | /** 426 | * 获取list缓存的长度 427 | * 428 | * @param key 键 429 | * @return 430 | */ 431 | public long lGetListSize(String key) { 432 | try { 433 | return redisTemplate.opsForList().size(key); 434 | } catch (Exception e) { 435 | e.printStackTrace(); 436 | return 0; 437 | } 438 | } 439 | 440 | /** 441 | * 通过索引 获取list中的值 442 | * 443 | * @param key 键 444 | * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 445 | * @return 446 | */ 447 | public Object lGetIndex(String key, long index) { 448 | try { 449 | return redisTemplate.opsForList().index(key, index); 450 | } catch (Exception e) { 451 | e.printStackTrace(); 452 | return null; 453 | } 454 | } 455 | 456 | /** 457 | * 将list放入缓存 458 | * 459 | * @param key 键 460 | * @param value 值 461 | * @return 462 | */ 463 | public boolean lSet(String key, Object value) { 464 | try { 465 | redisTemplate.opsForList().rightPush(key, value); 466 | return true; 467 | } catch (Exception e) { 468 | e.printStackTrace(); 469 | return false; 470 | } 471 | } 472 | 473 | /** 474 | * 将list放入缓存 475 | * 476 | * @param key 键 477 | * @param value 值 478 | * @param time 时间(秒) 479 | * @return 480 | */ 481 | public boolean lSet(String key, Object value, long time) { 482 | try { 483 | redisTemplate.opsForList().rightPush(key, value); 484 | if (time > 0) expire(key, time); 485 | return true; 486 | } catch (Exception e) { 487 | e.printStackTrace(); 488 | return false; 489 | } 490 | } 491 | 492 | /** 493 | * 将list放入缓存 494 | * 495 | * @param key 键 496 | * @param value 值 497 | * @return 498 | */ 499 | public boolean lSet(String key, List value) { 500 | try { 501 | redisTemplate.opsForList().rightPushAll(key, value); 502 | return true; 503 | } catch (Exception e) { 504 | e.printStackTrace(); 505 | return false; 506 | } 507 | } 508 | 509 | /** 510 | * 将list放入缓存 511 | * 512 | * @param key 键 513 | * @param value 值 514 | * @param time 时间(秒) 515 | * @return 516 | */ 517 | public boolean lSet(String key, List value, long time) { 518 | try { 519 | redisTemplate.opsForList().rightPushAll(key, value); 520 | if (time > 0) expire(key, time); 521 | return true; 522 | } catch (Exception e) { 523 | e.printStackTrace(); 524 | return false; 525 | } 526 | } 527 | 528 | /** 529 | * 根据索引修改list中的某条数据 530 | * 531 | * @param key 键 532 | * @param index 索引 533 | * @param value 值 534 | * @return 535 | */ 536 | public boolean lUpdateIndex(String key, long index, Object value) { 537 | try { 538 | redisTemplate.opsForList().set(key, index, value); 539 | return true; 540 | } catch (Exception e) { 541 | e.printStackTrace(); 542 | return false; 543 | } 544 | } 545 | 546 | /** 547 | * 移除N个值为value 548 | * 549 | * @param key 键 550 | * @param count 移除多少个 551 | * @param value 值 552 | * @return 移除的个数 553 | */ 554 | public long lRemove(String key, long count, Object value) { 555 | try { 556 | Long remove = redisTemplate.opsForList().remove(key, count, value); 557 | return remove; 558 | } catch (Exception e) { 559 | e.printStackTrace(); 560 | return 0; 561 | } 562 | } 563 | 564 | //================有序集合 sort set=================== 565 | /** 566 | * 有序set添加元素 567 | * 568 | * @param key 569 | * @param value 570 | * @param score 571 | * @return 572 | */ 573 | public boolean zSet(String key, Object value, double score) { 574 | return redisTemplate.opsForZSet().add(key, value, score); 575 | } 576 | 577 | public long batchZSet(String key, Set typles) { 578 | return redisTemplate.opsForZSet().add(key, typles); 579 | } 580 | 581 | public void zIncrementScore(String key, Object value, long delta) { 582 | redisTemplate.opsForZSet().incrementScore(key, value, delta); 583 | } 584 | 585 | public void zUnionAndStore(String key, Collection otherKeys, String destKey) { 586 | redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey); 587 | } 588 | 589 | /** 590 | * 获取zset数量 591 | * @param key 592 | * @param value 593 | * @return 594 | */ 595 | public long getZsetScore(String key, Object value) { 596 | Double score = redisTemplate.opsForZSet().score(key, value); 597 | if(score==null){ 598 | return 0; 599 | }else{ 600 | return score.longValue(); 601 | } 602 | } 603 | 604 | /** 605 | * 获取有序集 key 中成员 member 的排名 。 606 | * 其中有序集成员按 score 值递减 (从大到小) 排序。 607 | * @param key 608 | * @param start 609 | * @param end 610 | * @return 611 | */ 612 | public Set getZSetRank(String key, long start, long end) { 613 | return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end); 614 | } 615 | 616 | } --------------------------------------------------------------------------------