}
+ */
+export const generatorDynamicRouter = (data) => {
+ return new Promise((resolve, reject) => {
+ const resNav = data.antDesignmenus
+ const menuNav = []
+ const childrenNav = []
+ // 后端数据, 根级树数组, 根级 PID
+ listToTree(resNav, childrenNav, 0)
+
+ /**
+ * 增加静态网页
+ */
+ listToTree(userAccount, childrenNav, 0)
+ rootRouter.children = childrenNav
+ menuNav.push(rootRouter)
+ const routers = generator(menuNav)
+ routers.push(notFoundRouter)
+ resolve(routers)
+ }).catch(err => {
+ // reject('加载菜单失败')
+ return Promise.reject(err)
+ })
+}
+
+/**
+ * 格式化树形结构数据 生成 vue-router 层级路由表
+ *
+ * @param routerMap
+ * @param parent
+ * @returns {*}
+ */
+export const generator = (routerMap, parent) => {
+ return routerMap.map(item => {
+ // eslint-disable-next-line no-unused-vars
+ const { title, show, hideChildren, hiddenHeaderContent, target, icon, link } = item.meta || {}
+ const currentRouter = {
+ // 如果路由设置了 path,则作为默认 path,否则 路由地址 动态拼接生成如 /dashboard/workplace
+ path: item.path || `${parent && parent.path || ''}/${item.key}`,
+ // 路由名称,建议唯一
+ name: item.name || item.key || '',
+ // 该路由对应页面的 组件 :方案1
+ // component: constantRouterComponents[item.component || item.key],
+ // 该路由对应页面的 组件 :方案2 (动态加载)
+ component: (constantRouterComponents[item.component || item.key]) || (() => import(`@/views/${item.component}`)),
+ // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
+ meta: {
+ title: title,
+ icon: icon || undefined,
+ // hiddenHeaderContent: hiddenHeaderContent,
+ target: target,
+ link: link
+ }
+ }
+ // 是否设置了隐藏菜单
+ if (show === false) {
+ currentRouter.hidden = true
+ }
+ // 是否设置了隐藏子菜单
+ if (hideChildren) {
+ currentRouter.hideChildrenInMenu = true
+ }
+ // 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
+ if (!currentRouter.path.startsWith('http')) {
+ currentRouter.path = currentRouter.path.replace('//', '/')
+ }
+ // 重定向
+ item.redirect && (currentRouter.redirect = item.redirect)
+ // 是否有子菜单,并递归处理
+ if (item.children && item.children.length > 0) {
+ // Recursion
+ currentRouter.children = generator(item.children, currentRouter)
+ }
+ return currentRouter
+ })
+}
+
+/**
+ * 数组转树形结构
+ * @param list 源数组
+ * @param tree 树
+ * @param parentId 父ID
+ */
+const listToTree = (list, tree, parentId) => {
+ list.forEach(item => {
+ // 判断是否为父级菜单
+ // eslint-disable-next-line eqeqeq
+ if (item.pid == parentId) {
+ const child = {
+ ...item,
+ key: item.key || item.name,
+ children: []
+ }
+ // 迭代 list, 找到当前菜单相符合的所有子菜单
+ listToTree(list, child.children, item.id)
+ // 删掉不存在 children 值的属性
+ if (child.children.length <= 0) {
+ delete child.children
+ }
+ // 加入到树中
+ tree.push(child)
+ }
+ })
+}
diff --git a/_web/src/router/index.js b/_web/src/router/index.js
new file mode 100644
index 00000000..dd727723
--- /dev/null
+++ b/_web/src/router/index.js
@@ -0,0 +1,19 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import { constantRouterMap } from '@/config/router.config'
+
+// hack router push callback
+const originalPush = Router.prototype.push
+Router.prototype.push = function push (location, onResolve, onReject) {
+ if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
+ return originalPush.call(this, location).catch(err => err)
+}
+
+Vue.use(Router)
+
+export default new Router({
+ mode: 'history',
+ base: process.env.BASE_URL,
+ scrollBehavior: () => ({ y: 0 }),
+ routes: constantRouterMap
+})
diff --git a/_web/src/store/getters.js b/_web/src/store/getters.js
new file mode 100644
index 00000000..69929b90
--- /dev/null
+++ b/_web/src/store/getters.js
@@ -0,0 +1,18 @@
+const getters = {
+ device: state => state.app.device,
+ theme: state => state.app.theme,
+ color: state => state.app.color,
+ token: state => state.user.token,
+ avatar: state => state.user.avatar,
+ nickname: state => state.user.name,
+ welcome: state => state.user.welcome,
+ roles: state => state.user.roles,
+ buttons: state => state.user.buttons,
+ admintype: state => state.user.admintype,
+ userInfo: state => state.user.info,
+ addRouters: state => state.permission.addRouters,
+ multiTab: state => state.app.multiTab,
+ lang: state => state.i18n.lang
+}
+
+export default getters
diff --git a/_web/src/store/index.js b/_web/src/store/index.js
new file mode 100644
index 00000000..687d21b2
--- /dev/null
+++ b/_web/src/store/index.js
@@ -0,0 +1,32 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+import app from './modules/app'
+import user from './modules/user'
+
+// default router permission control
+// import permission from './modules/permission'
+
+// dynamic router permission control (Experimental)
+import permission from './modules/async-router'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+ modules: {
+ app,
+ user,
+ permission
+ },
+ state: {
+
+ },
+ mutations: {
+
+ },
+ actions: {
+
+ },
+ getters
+})
diff --git a/_web/src/store/modules/app.js b/_web/src/store/modules/app.js
new file mode 100644
index 00000000..373a97eb
--- /dev/null
+++ b/_web/src/store/modules/app.js
@@ -0,0 +1,122 @@
+import Vue from 'vue'
+import {
+ SIDEBAR_TYPE,
+ DEFAULT_THEME,
+ DEFAULT_LAYOUT_MODE,
+ DEFAULT_COLOR,
+ DEFAULT_COLOR_WEAK,
+ DEFAULT_FIXED_HEADER,
+ DEFAULT_FIXED_SIDEMENU,
+ DEFAULT_FIXED_HEADER_HIDDEN,
+ DEFAULT_CONTENT_WIDTH_TYPE,
+ DEFAULT_MULTI_TAB
+} from '@/store/mutation-types'
+
+const app = {
+ state: {
+ sidebar: true,
+ device: 'desktop',
+ theme: '',
+ layout: '',
+ contentWidth: '',
+ fixedHeader: false,
+ fixSiderbar: false,
+ autoHideHeader: false,
+ color: null,
+ weak: false,
+ multiTab: true
+ },
+ mutations: {
+ SET_SIDEBAR_TYPE: (state, type) => {
+ state.sidebar = type
+ Vue.ls.set(SIDEBAR_TYPE, type)
+ },
+ CLOSE_SIDEBAR: (state) => {
+ Vue.ls.set(SIDEBAR_TYPE, true)
+ state.sidebar = false
+ },
+ TOGGLE_DEVICE: (state, device) => {
+ state.device = device
+ },
+ TOGGLE_THEME: (state, theme) => {
+ // setStore('_DEFAULT_THEME', theme)
+ Vue.ls.set(DEFAULT_THEME, theme)
+ state.theme = theme
+ },
+ TOGGLE_LAYOUT_MODE: (state, layout) => {
+ Vue.ls.set(DEFAULT_LAYOUT_MODE, layout)
+ state.layout = layout
+ },
+ TOGGLE_FIXED_HEADER: (state, fixed) => {
+ Vue.ls.set(DEFAULT_FIXED_HEADER, fixed)
+ state.fixedHeader = fixed
+ },
+ TOGGLE_FIXED_SIDERBAR: (state, fixed) => {
+ Vue.ls.set(DEFAULT_FIXED_SIDEMENU, fixed)
+ state.fixSiderbar = fixed
+ },
+ TOGGLE_FIXED_HEADER_HIDDEN: (state, show) => {
+ Vue.ls.set(DEFAULT_FIXED_HEADER_HIDDEN, show)
+ state.autoHideHeader = show
+ },
+ TOGGLE_CONTENT_WIDTH: (state, type) => {
+ Vue.ls.set(DEFAULT_CONTENT_WIDTH_TYPE, type)
+ state.contentWidth = type
+ },
+ TOGGLE_COLOR: (state, color) => {
+ Vue.ls.set(DEFAULT_COLOR, color)
+ state.color = color
+ },
+ TOGGLE_WEAK: (state, flag) => {
+ Vue.ls.set(DEFAULT_COLOR_WEAK, flag)
+ state.weak = flag
+ },
+ TOGGLE_MULTI_TAB: (state, bool) => {
+ Vue.ls.set(DEFAULT_MULTI_TAB, bool)
+ state.multiTab = bool
+ }
+ },
+ actions: {
+ setSidebar ({ commit }, type) {
+ commit('SET_SIDEBAR_TYPE', type)
+ },
+ CloseSidebar ({ commit }) {
+ commit('CLOSE_SIDEBAR')
+ },
+ ToggleDevice ({ commit }, device) {
+ commit('TOGGLE_DEVICE', device)
+ },
+ ToggleTheme ({ commit }, theme) {
+ commit('TOGGLE_THEME', theme)
+ },
+ ToggleLayoutMode ({ commit }, mode) {
+ commit('TOGGLE_LAYOUT_MODE', mode)
+ },
+ ToggleFixedHeader ({ commit }, fixedHeader) {
+ if (!fixedHeader) {
+ commit('TOGGLE_FIXED_HEADER_HIDDEN', false)
+ }
+ commit('TOGGLE_FIXED_HEADER', fixedHeader)
+ },
+ ToggleFixSiderbar ({ commit }, fixSiderbar) {
+ commit('TOGGLE_FIXED_SIDERBAR', fixSiderbar)
+ },
+ ToggleFixedHeaderHidden ({ commit }, show) {
+ commit('TOGGLE_FIXED_HEADER_HIDDEN', show)
+ },
+ ToggleContentWidth ({ commit }, type) {
+ commit('TOGGLE_CONTENT_WIDTH', type)
+ },
+ ToggleColor ({ commit }, color) {
+ commit('TOGGLE_COLOR', color)
+ },
+ ToggleWeak ({ commit }, weakFlag) {
+ commit('TOGGLE_WEAK', weakFlag)
+ },
+ ToggleMultiTab ({ commit }, bool) {
+ commit('TOGGLE_MULTI_TAB', bool)
+ }
+ }
+}
+
+export default app
diff --git a/_web/src/store/modules/async-router.js b/_web/src/store/modules/async-router.js
new file mode 100644
index 00000000..4491e06a
--- /dev/null
+++ b/_web/src/store/modules/async-router.js
@@ -0,0 +1,33 @@
+/**
+ * 向后端请求用户的菜单,动态生成路由
+ */
+import { constantRouterMap } from '@/config/router.config'
+import { generatorDynamicRouter } from '@/router/generator-routers'
+
+const permission = {
+ state: {
+ routers: constantRouterMap,
+ addRouters: []
+ },
+ mutations: {
+ SET_ROUTERS: (state, routers) => {
+ state.addRouters = routers
+ state.routers = constantRouterMap.concat(routers)
+ }
+ },
+ actions: {
+ GenerateRoutes ({ commit }, data) {
+ return new Promise(resolve => {
+ generatorDynamicRouter(data).then(routers => {
+ commit('SET_ROUTERS', routers)
+ resolve()
+ })
+ }).catch(err => {
+ // eslint-disable-next-line no-undef
+ reject(err)
+ })
+ }
+ }
+}
+
+export default permission
diff --git a/_web/src/store/modules/permission.js b/_web/src/store/modules/permission.js
new file mode 100644
index 00000000..0e5e5c3e
--- /dev/null
+++ b/_web/src/store/modules/permission.js
@@ -0,0 +1,77 @@
+import { asyncRouterMap, constantRouterMap } from '@/config/router.config'
+
+/**
+ * 过滤账户是否拥有某一个权限,并将菜单从加载列表移除
+ *
+ * @param permission
+ * @param route
+ * @returns {boolean}
+ */
+function hasPermission (permission, route) {
+ // if (route.meta && route.meta.permission) {
+ // let flag = false
+ // for (let i = 0, len = permission.length; i < len; i++) {
+ // flag = route.meta.permission.includes(permission[i])
+ // if (flag) {
+ // return true
+ // }
+ // }
+ // return false
+ // }
+ return true
+}
+
+/**
+ * 单账户多角色时,使用该方法可过滤角色不存在的菜单
+ *
+ * @param roles
+ * @param route
+ * @returns {*}
+ */
+// eslint-disable-next-line
+function hasRole(roles, route) {
+ if (route.meta && route.meta.roles) {
+ return route.meta.roles.includes(roles.id)
+ } else {
+ return true
+ }
+}
+
+function filterAsyncRouter (routerMap, roles) {
+ const accessedRouters = routerMap.filter(route => {
+ if (hasPermission(roles.permissionList, route)) {
+ if (route.children && route.children.length) {
+ route.children = filterAsyncRouter(route.children, roles)
+ }
+ return true
+ }
+ return false
+ })
+ return accessedRouters
+}
+
+const permission = {
+ state: {
+ routers: constantRouterMap,
+ addRouters: []
+ },
+ mutations: {
+ SET_ROUTERS: (state, routers) => {
+ state.addRouters = routers
+ state.routers = constantRouterMap.concat(routers)
+ }
+ },
+ actions: {
+ GenerateRoutes ({ commit }, data) {
+ return new Promise(resolve => {
+ const { roles } = data
+ const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
+ // console.log('动态获取到的菜单列表:'+JSON.stringify(accessedRouters))
+ commit('SET_ROUTERS', accessedRouters)
+ resolve()
+ })
+ }
+ }
+}
+
+export default permission
diff --git a/_web/src/store/modules/user.js b/_web/src/store/modules/user.js
new file mode 100644
index 00000000..0382b32d
--- /dev/null
+++ b/_web/src/store/modules/user.js
@@ -0,0 +1,172 @@
+import Vue from 'vue'
+import { login, getLoginUser, logout } from '@/api/modular/system/loginManage'
+import { sysDictTypeTree } from '@/api/modular/system/dictManage'
+import { sysMenuChange } from '@/api/modular/system/menuManage'
+import { ACCESS_TOKEN, ALL_APPS_MENU, DICT_TYPE_TREE_DATA } from '@/store/mutation-types'
+
+import { welcome } from '@/utils/util'
+import store from '../index'
+import router from '../../router'
+
+const user = {
+ state: {
+ token: '',
+ name: '',
+ welcome: '',
+ avatar: '',
+ buttons: [], // 按钮权限
+ admintype: '', // 是否是超管
+ roles: [],
+ info: {}
+ },
+
+ mutations: {
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_NAME: (state, { name, welcome }) => {
+ state.name = name
+ state.welcome = welcome
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ },
+ SET_ROLES: (state, roles) => {
+ state.roles = roles
+ },
+ SET_INFO: (state, info) => {
+ state.info = info
+ },
+ SET_BUTTONS: (state, buttons) => {
+ state.buttons = buttons
+ },
+ SET_ADMINTYPE: (state, admintype) => {
+ state.admintype = admintype
+ }
+ },
+
+ actions: {
+ // 登录
+ Login ({ commit }, userInfo) {
+ return new Promise((resolve, reject) => {
+ login(userInfo).then(response => {
+ if (!response.success) {
+ reject(response.message)
+ return
+ }
+ const result = response.data
+ Vue.ls.set(ACCESS_TOKEN, result, 7 * 24 * 60 * 60 * 1000)
+ commit('SET_TOKEN', result)
+ resolve()
+ // eslint-disable-next-line handle-callback-err
+ }).catch(error => {
+ // eslint-disable-next-line prefer-promise-reject-errors
+ reject('后端未启动或代理错误')
+ })
+ })
+ },
+
+ // 获取用户信息
+ GetInfo ({ commit }) {
+ return new Promise((resolve, reject) => {
+ getLoginUser().then(response => {
+ if (response.success) {
+ const data = response.data
+ commit('SET_ADMINTYPE', data.adminType)
+ commit('SET_ROLES', 1)
+ commit('SET_BUTTONS', data.permissions)
+ commit('SET_INFO', data)
+ commit('SET_NAME', { name: data.name, welcome: welcome() })
+ if (data.avatar != null) {
+ commit('SET_AVATAR', process.env.VUE_APP_API_BASE_URL + '/sysFileInfo/preview?id=' + data.avatar)
+ }
+ resolve(data)
+ } else {
+ // eslint-disable-next-line no-undef
+ reject(new Error(data.message))
+ }
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 登出
+ Logout ({ commit, state }) {
+ return new Promise((resolve) => {
+ logout(state.token).then(() => {
+ resolve()
+ }).catch(() => {
+ resolve()
+ }).finally(() => {
+ commit('SET_TOKEN', '')
+ commit('SET_ROLES', [])
+ commit('SET_BUTTONS', [])
+ commit('SET_ADMINTYPE', '')
+ Vue.ls.remove(ACCESS_TOKEN)
+ Vue.ls.remove(ALL_APPS_MENU)
+ Vue.ls.remove(DICT_TYPE_TREE_DATA)
+ })
+ })
+ },
+
+ // 加载所有字典数据
+ dictTypeData () {
+ return new Promise((resolve, reject) => {
+ sysDictTypeTree().then((data) => {
+ if (data.success) {
+ const result = data.data
+ Vue.ls.set(DICT_TYPE_TREE_DATA, result)
+ resolve()
+ } else {
+ // eslint-disable-next-line no-undef
+ reject(new Error(data.message))
+ }
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 切换应用菜单
+ MenuChange ({ commit }, application) {
+ return new Promise((resolve) => {
+ sysMenuChange({ application: application.code }).then((res) => {
+ const apps = { 'code': '', 'name': '', 'active': '', 'menu': '' }
+ apps.active = true
+ apps.menu = res.data
+ // eslint-disable-next-line camelcase
+ const all_app_menu = Vue.ls.get(ALL_APPS_MENU)
+ // eslint-disable-next-line camelcase
+ const new_false_all_app_menu = []
+ // 先去除所有默认的,以为此时切换的即将成为前端缓存默认的应用
+ all_app_menu.forEach(item => {
+ if (item.active) {
+ item.active = false
+ }
+ new_false_all_app_menu.push(item)
+ })
+ // 此时缓存中全部都是不默认的应用
+ Vue.ls.set(ALL_APPS_MENU, new_false_all_app_menu)
+ apps.name = application.name
+ apps.code = application.code
+ const applocationR = []
+ applocationR.push(apps)
+ Vue.ls.set(ALL_APPS_MENU, applocationR)
+ resolve(res)
+ const antDesignmenus = res.data
+ store.dispatch('GenerateRoutes', { antDesignmenus }).then(() => {
+ router.addRoutes(store.getters.addRouters)
+ })
+ // 切换应用刷新整体界面,暂且取消
+ // window.location.reload()
+ }).catch(() => {
+ resolve()
+ })
+ })
+ }
+
+ }
+}
+
+export default user
diff --git a/_web/src/store/mutation-types.js b/_web/src/store/mutation-types.js
new file mode 100644
index 00000000..819c3125
--- /dev/null
+++ b/_web/src/store/mutation-types.js
@@ -0,0 +1,18 @@
+export const ACCESS_TOKEN = 'Access-Token'
+export const SIDEBAR_TYPE = 'SIDEBAR_TYPE'
+export const ALL_APPS_MENU = 'ALL_APPS_MENU'
+export const DEFAULT_THEME = 'DEFAULT_THEME'
+export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE'
+export const DEFAULT_COLOR = 'DEFAULT_COLOR'
+export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK'
+export const DEFAULT_FIXED_HEADER = 'DEFAULT_FIXED_HEADER'
+export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU'
+export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'
+export const DEFAULT_CONTENT_WIDTH_TYPE = 'DEFAULT_CONTENT_WIDTH_TYPE'
+export const DEFAULT_MULTI_TAB = 'DEFAULT_MULTI_TAB'
+export const DICT_TYPE_TREE_DATA = 'DICT_TYPE_TREE_DATA'
+
+export const CONTENT_WIDTH_TYPE = {
+ Fluid: 'Fluid',
+ Fixed: 'Fixed'
+}
diff --git a/_web/src/utils/applocation.js b/_web/src/utils/applocation.js
new file mode 100644
index 00000000..30fdc289
--- /dev/null
+++ b/_web/src/utils/applocation.js
@@ -0,0 +1,11 @@
+import store from '@/store'
+
+/**
+ * 缓存中的已选中应用
+ *
+ * @author yubaoshan
+ * @date 2020/06/27 02:34
+ */
+export function sysApplication () {
+ return store.getters.applocation
+}
diff --git a/_web/src/utils/axios.js b/_web/src/utils/axios.js
new file mode 100644
index 00000000..3b91f6b5
--- /dev/null
+++ b/_web/src/utils/axios.js
@@ -0,0 +1,35 @@
+const VueAxios = {
+ vm: {},
+ // eslint-disable-next-line no-unused-vars
+ install (Vue, instance) {
+ if (this.installed) {
+ return
+ }
+ this.installed = true
+
+ if (!instance) {
+ // eslint-disable-next-line no-console
+ console.error('You have to install axios')
+ return
+ }
+
+ Vue.axios = instance
+
+ Object.defineProperties(Vue.prototype, {
+ axios: {
+ get: function get () {
+ return instance
+ }
+ },
+ $http: {
+ get: function get () {
+ return instance
+ }
+ }
+ })
+ }
+}
+
+export {
+ VueAxios
+}
diff --git a/_web/src/utils/device.js b/_web/src/utils/device.js
new file mode 100644
index 00000000..0f350f36
--- /dev/null
+++ b/_web/src/utils/device.js
@@ -0,0 +1,33 @@
+import enquireJs from 'enquire.js'
+
+export const DEVICE_TYPE = {
+ DESKTOP: 'desktop',
+ TABLET: 'tablet',
+ MOBILE: 'mobile'
+}
+
+export const deviceEnquire = function (callback) {
+ const matchDesktop = {
+ match: () => {
+ callback && callback(DEVICE_TYPE.DESKTOP)
+ }
+ }
+
+ const matchLablet = {
+ match: () => {
+ callback && callback(DEVICE_TYPE.TABLET)
+ }
+ }
+
+ const matchMobile = {
+ match: () => {
+ callback && callback(DEVICE_TYPE.MOBILE)
+ }
+ }
+
+ // screen and (max-width: 1087.99px)
+ enquireJs
+ .register('screen and (max-width: 576px)', matchMobile)
+ .register('screen and (min-width: 576px) and (max-width: 1199px)', matchLablet)
+ .register('screen and (min-width: 1200px)', matchDesktop)
+}
diff --git a/_web/src/utils/domUtil.js b/_web/src/utils/domUtil.js
new file mode 100644
index 00000000..47996707
--- /dev/null
+++ b/_web/src/utils/domUtil.js
@@ -0,0 +1,19 @@
+export const setDocumentTitle = function (title) {
+ document.title = title
+ const ua = navigator.userAgent
+ // eslint-disable-next-line
+ const regex = /\bMicroMessenger\/([\d\.]+)/
+ if (regex.test(ua) && /ip(hone|od|ad)/i.test(ua)) {
+ const i = document.createElement('iframe')
+ i.src = '/favicon.ico'
+ i.style.display = 'none'
+ i.onload = function () {
+ setTimeout(function () {
+ i.remove()
+ }, 9)
+ }
+ document.body.appendChild(i)
+ }
+}
+
+export const domTitle = 'XiaoNuo'
diff --git a/_web/src/utils/filter.js b/_web/src/utils/filter.js
new file mode 100644
index 00000000..09b629f6
--- /dev/null
+++ b/_web/src/utils/filter.js
@@ -0,0 +1,91 @@
+import Vue from 'vue'
+import { DICT_TYPE_TREE_DATA } from '@/store/mutation-types'
+import moment from 'moment'
+import 'moment/locale/zh-cn'
+moment.locale('zh-cn')
+
+Vue.filter('NumberFormat', function (value) {
+ if (!value) {
+ return '0'
+ }
+ const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') // 将整数部分逢三一断
+ return intPartFormat
+})
+
+Vue.filter('dayjs', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
+ return moment(dataStr).format(pattern)
+})
+
+Vue.filter('moment', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
+ return moment(dataStr).format(pattern)
+})
+
+/**
+ * 金额格式化 ,使用方法:{{ val | Fmoney }}
+ *
+ * @author yubaoshan
+ * @date 2020-9-15 15:02:20
+ */
+Vue.filter('Fmoney', function (val) {
+ // eslint-disable-next-line no-useless-escape
+ val = val.toString().replace(/\$|\,/g, '')
+ if (isNaN(val)) {
+ val = '0'
+ }
+ // eslint-disable-next-line eqeqeq
+ const sign = (val == (val = Math.abs(val)))
+ val = Math.floor(val * 100 + 0.50000000001)
+ let cents = val % 100
+ val = Math.floor(val / 100).toString()
+ if (cents < 10) {
+ cents = '0' + cents
+ }
+ // eslint-disable-next-line no-undef
+ for (let i = 0; i < Math.floor((val.length - (1 + i)) / 3); I++) {
+ val = val.substring(0, val.length - (4 * i + 3)) + ',' + val.substring(val.length - (4 * i + 3))
+ }
+ return (((sign) ? '' : '-') + val + '.' + cents)
+})
+
+/**
+ * 翻译使用方法,直接返回翻译后的name {{ code | dictType(value) }}
+ *
+ * @author yubaoshan
+ * @date 2020-9-15 15:02:20
+ */
+Vue.filter('dictType', function (code, value) {
+ const dictTypeTree = Vue.ls.get(DICT_TYPE_TREE_DATA)
+ if (dictTypeTree === undefined) {
+ return '需重新登录'
+ }
+ // eslint-disable-next-line eqeqeq
+ const tree = dictTypeTree.filter(item => item.code == code)[0].children
+ if (tree === undefined || tree.length === 0) {
+ return '无此字典'
+ }
+ // eslint-disable-next-line eqeqeq
+ const values = tree.filter(item => item.code == value)
+ if (values.length === undefined || values.length === 0) {
+ return '无此字典'
+ }
+ return values[0].name
+})
+
+/**
+ * 获取某个code下字典的列表,多用于字典下拉框,使用方法:{{ code | dictData }}
+ *
+ * @author yubaoshan
+ * @date 2020-9-19 22:40:22
+ */
+Vue.filter('dictData', function (code) {
+ const dictTypeTree = Vue.ls.get(DICT_TYPE_TREE_DATA)
+ if (dictTypeTree === undefined) {
+ return []
+ }
+ // eslint-disable-next-line eqeqeq
+ const tree = dictTypeTree.filter(item => item.code == code)[0].children
+ if (tree === undefined) {
+ return []
+ }
+ return tree
+})
diff --git a/_web/src/utils/helper/permission.js b/_web/src/utils/helper/permission.js
new file mode 100644
index 00000000..f0f6a32c
--- /dev/null
+++ b/_web/src/utils/helper/permission.js
@@ -0,0 +1,51 @@
+export const PERMISSION_ENUM = {
+ 'add': { key: 'add', label: '新增' },
+ 'delete': { key: 'delete', label: '删除' },
+ 'edit': { key: 'edit', label: '修改' },
+ 'query': { key: 'query', label: '查询' },
+ 'get': { key: 'get', label: '详情' },
+ 'enable': { key: 'enable', label: '启用' },
+ 'disable': { key: 'disable', label: '禁用' },
+ 'import': { key: 'import', label: '导入' },
+ 'export': { key: 'export', label: '导出' }
+}
+
+function plugin (Vue) {
+ if (plugin.installed) {
+ return
+ }
+
+ !Vue.prototype.$auth && Object.defineProperties(Vue.prototype, {
+ $auth: {
+ get () {
+ const _this = this
+ return (permissions) => {
+ const [permission, action] = permissions.split('.')
+ const permissionList = _this.$store.getters.roles.permissions
+ return permissionList.find((val) => {
+ return val.permissionId === permission
+ }).actionList.findIndex((val) => {
+ return val === action
+ }) > -1
+ }
+ }
+ }
+ })
+
+ !Vue.prototype.$enum && Object.defineProperties(Vue.prototype, {
+ $enum: {
+ get () {
+ // const _this = this;
+ return (val) => {
+ let result = PERMISSION_ENUM
+ val && val.split('.').forEach(v => {
+ result = result && result[v] || null
+ })
+ return result
+ }
+ }
+ }
+ })
+}
+
+export default plugin
diff --git a/_web/src/utils/mixin.js b/_web/src/utils/mixin.js
new file mode 100644
index 00000000..217732d2
--- /dev/null
+++ b/_web/src/utils/mixin.js
@@ -0,0 +1,76 @@
+// import Vue from 'vue'
+import { deviceEnquire, DEVICE_TYPE } from '@/utils/device'
+import { mapState } from 'vuex'
+
+// const mixinsComputed = Vue.config.optionMergeStrategies.computed
+// const mixinsMethods = Vue.config.optionMergeStrategies.methods
+
+const mixin = {
+ computed: {
+ ...mapState({
+ layoutMode: state => state.app.layout,
+ navTheme: state => state.app.theme,
+ primaryColor: state => state.app.color,
+ colorWeak: state => state.app.weak,
+ fixedHeader: state => state.app.fixedHeader,
+ fixSiderbar: state => state.app.fixSiderbar,
+ fixSidebar: state => state.app.fixSiderbar,
+ contentWidth: state => state.app.contentWidth,
+ autoHideHeader: state => state.app.autoHideHeader,
+ sidebarOpened: state => state.app.sidebar,
+ multiTab: state => state.app.multiTab
+ })
+ },
+ methods: {
+ isTopMenu () {
+ return this.layoutMode === 'topmenu'
+ },
+ isSideMenu () {
+ return !this.isTopMenu()
+ }
+ }
+}
+
+const mixinDevice = {
+ computed: {
+ ...mapState({
+ device: state => state.app.device
+ })
+ },
+ methods: {
+ isMobile () {
+ return this.device === DEVICE_TYPE.MOBILE
+ },
+ isDesktop () {
+ return this.device === DEVICE_TYPE.DESKTOP
+ },
+ isTablet () {
+ return this.device === DEVICE_TYPE.TABLET
+ }
+ }
+}
+
+const AppDeviceEnquire = {
+ mounted () {
+ const { $store } = this
+ deviceEnquire(deviceType => {
+ switch (deviceType) {
+ case DEVICE_TYPE.DESKTOP:
+ $store.commit('TOGGLE_DEVICE', 'desktop')
+ $store.dispatch('setSidebar', true)
+ break
+ case DEVICE_TYPE.TABLET:
+ $store.commit('TOGGLE_DEVICE', 'tablet')
+ $store.dispatch('setSidebar', false)
+ break
+ case DEVICE_TYPE.MOBILE:
+ default:
+ $store.commit('TOGGLE_DEVICE', 'mobile')
+ $store.dispatch('setSidebar', true)
+ break
+ }
+ })
+ }
+}
+
+export { mixin, AppDeviceEnquire, mixinDevice }
diff --git a/_web/src/utils/permissions.js b/_web/src/utils/permissions.js
new file mode 100644
index 00000000..ce0376fd
--- /dev/null
+++ b/_web/src/utils/permissions.js
@@ -0,0 +1,26 @@
+import store from '@/store'
+
+export function actionToObject (json) {
+ try {
+ return JSON.parse(json)
+ } catch (e) {
+ console.log('err', e.message)
+ }
+ return []
+}
+
+/**
+ * 控制按钮是否显示
+ *
+ * @author yubaoshan
+ * @date 2020/06/27 02:34
+ */
+export function hasBtnPermission (permission) {
+ const myBtns = store.getters.buttons
+ const admintype = store.getters.admintype
+ // eslint-disable-next-line eqeqeq
+ if (admintype == '1') {
+ return true
+ }
+ return myBtns.indexOf(permission) > -1
+}
diff --git a/_web/src/utils/request.js b/_web/src/utils/request.js
new file mode 100644
index 00000000..b59a59e8
--- /dev/null
+++ b/_web/src/utils/request.js
@@ -0,0 +1,94 @@
+import Vue from 'vue'
+import axios from 'axios'
+import store from '@/store'
+import { message, Modal, notification } from 'ant-design-vue' /// es/notification
+import { VueAxios } from './axios'
+import { ACCESS_TOKEN } from '@/store/mutation-types'
+
+// 创建 axios 实例
+const service = axios.create({
+ baseURL: '/api', // api base_url
+ timeout: 6000 // 请求超时时间
+})
+
+const err = (error) => {
+ if (error.response) {
+ const data = error.response.data
+ const token = Vue.ls.get(ACCESS_TOKEN)
+
+ if (error.response.status === 403) {
+ console.log('服务器403啦,要重新登录!')
+ notification.error({
+ message: 'Forbidden',
+ description: data.message
+ })
+ }
+ if (error.response.status === 500) {
+ if (data.message.length > 0) {
+ message.error(data.message)
+ }
+ }
+ if (error.response.status === 401 && !(data.result && data.result.isLogin)) {
+ notification.error({
+ message: 'Unauthorized',
+ description: 'Authorization verification failed'
+ })
+ if (token) {
+ store.dispatch('Logout').then(() => {
+ setTimeout(() => {
+ window.location.reload()
+ }, 1500)
+ })
+ }
+ }
+ }
+ return Promise.reject(error)
+}
+
+// request interceptor
+service.interceptors.request.use(config => {
+ const token = Vue.ls.get(ACCESS_TOKEN)
+ if (token) {
+ config.headers['Authorization'] = 'Bearer ' + token
+ }
+ return config
+}, err)
+
+/**
+ * response interceptor
+ * 所有请求统一返回
+ */
+service.interceptors.response.use((response) => {
+ if (response.request.responseType === 'blob') {
+ return response
+ }
+ const code = response.data.code
+ if (code === 1011006 || code === 1011007 || code === 1011008 || code === 1011009) {
+ Modal.error({
+ title: '提示:',
+ content: response.data.message,
+ okText: '重新登录',
+ onOk: () => {
+ Vue.ls.remove(ACCESS_TOKEN)
+ window.location.reload()
+ }
+ })
+ } else if (code === 1013002 || code === 1016002 || code === 1015002) {
+ message.error(response.data.message)
+ return response.data
+ } else {
+ return response.data
+ }
+}, err)
+
+const installer = {
+ vm: {},
+ install (Vue) {
+ Vue.use(VueAxios, service)
+ }
+}
+
+export {
+ installer as VueAxios,
+ service as axios
+}
diff --git a/_web/src/utils/routeConvert.js b/_web/src/utils/routeConvert.js
new file mode 100644
index 00000000..e88b0d6d
--- /dev/null
+++ b/_web/src/utils/routeConvert.js
@@ -0,0 +1,30 @@
+import cloneDeep from 'lodash.clonedeep'
+
+export function convertRoutes (nodes) {
+ if (!nodes) return null
+
+ nodes = cloneDeep(nodes)
+
+ let queue = Array.isArray(nodes) ? nodes.concat() : [nodes]
+
+ while (queue.length) {
+ const levelSize = queue.length
+
+ for (let i = 0; i < levelSize; i++) {
+ const node = queue.shift()
+
+ if (!node.children || !node.children.length) continue
+
+ node.children.forEach(child => {
+ // 转化相对路径
+ if (child.path[0] !== '/' && !child.path.startsWith('http')) {
+ child.path = node.path.replace(/(\w*)[/]*$/, `$1/${child.path}`)
+ }
+ })
+
+ queue = queue.concat(node.children)
+ }
+ }
+
+ return nodes
+}
diff --git a/_web/src/utils/util.js b/_web/src/utils/util.js
new file mode 100644
index 00000000..311f7461
--- /dev/null
+++ b/_web/src/utils/util.js
@@ -0,0 +1,67 @@
+export function timeFix () {
+ const time = new Date()
+ const hour = time.getHours()
+ return hour < 9 ? '早上好' : hour <= 11 ? '上午好' : hour <= 13 ? '中午好' : hour < 20 ? '下午好' : '晚上好'
+}
+
+export function welcome () {
+ const arr = ['休息一会儿吧', '准备吃什么呢?', '要不要打一把 LOL', '我猜你可能累了']
+ const index = Math.floor(Math.random() * arr.length)
+ return arr[index]
+}
+
+/**
+ * 触发 window.resize
+ */
+export function triggerWindowResizeEvent () {
+ const event = document.createEvent('HTMLEvents')
+ event.initEvent('resize', true, true)
+ event.eventType = 'message'
+ window.dispatchEvent(event)
+}
+
+export function handleScrollHeader (callback) {
+ let timer = 0
+
+ let beforeScrollTop = window.pageYOffset
+ callback = callback || function () {}
+ window.addEventListener(
+ 'scroll',
+ event => {
+ clearTimeout(timer)
+ timer = setTimeout(() => {
+ let direction = 'up'
+ const afterScrollTop = window.pageYOffset
+ const delta = afterScrollTop - beforeScrollTop
+ if (delta === 0) {
+ return false
+ }
+ direction = delta > 0 ? 'down' : 'up'
+ callback(direction)
+ beforeScrollTop = afterScrollTop
+ }, 50)
+ },
+ false
+ )
+}
+
+export function isIE () {
+ const bw = window.navigator.userAgent
+ const compare = (s) => bw.indexOf(s) >= 0
+ const ie11 = (() => 'ActiveXObject' in window)()
+ return compare('MSIE') || ie11
+}
+
+/**
+ * Remove loading animate
+ * @param id parent element id or class
+ * @param timeout
+ */
+export function removeLoadingAnimate (id = '', timeout = 1500) {
+ if (id === '') {
+ return
+ }
+ setTimeout(() => {
+ document.body.removeChild(document.getElementById(id))
+ }, timeout)
+}
diff --git a/_web/src/utils/utils.less b/_web/src/utils/utils.less
new file mode 100644
index 00000000..ba75a67f
--- /dev/null
+++ b/_web/src/utils/utils.less
@@ -0,0 +1,50 @@
+.textOverflow() {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ word-break: break-all;
+}
+
+.textOverflowMulti(@line: 3, @bg: #fff) {
+ position: relative;
+ max-height: @line * 1.5em;
+ margin-right: -1em;
+ padding-right: 1em;
+ overflow: hidden;
+ line-height: 1.5em;
+ text-align: justify;
+ &::before {
+ position: absolute;
+ right: 14px;
+ bottom: 0;
+ padding: 0 1px;
+ background: @bg;
+ content: '...';
+ }
+ &::after {
+ position: absolute;
+ right: 14px;
+ width: 1em;
+ height: 1em;
+ margin-top: 0.2em;
+ background: white;
+ content: '';
+ }
+}
+
+// mixins for clearfix
+// ------------------------
+.clearfix() {
+ zoom: 1;
+ &::before,
+ &::after {
+ display: table;
+ content: ' ';
+ }
+ &::after {
+ clear: both;
+ height: 0;
+ font-size: 0;
+ visibility: hidden;
+ }
+}
\ No newline at end of file
diff --git a/_web/src/views/404.vue b/_web/src/views/404.vue
new file mode 100644
index 00000000..8c1d8a18
--- /dev/null
+++ b/_web/src/views/404.vue
@@ -0,0 +1,15 @@
+
+
+ 404 page
+
+
+
+
+
+
diff --git a/_web/src/views/Home.vue b/_web/src/views/Home.vue
new file mode 100644
index 00000000..f67c95f5
--- /dev/null
+++ b/_web/src/views/Home.vue
@@ -0,0 +1,215 @@
+
+
+
+
+
Welcome to Your Vue.js App
+
+
+
+
+
# Trend 组件
+
+
正常
+
+
+
+
+ 工资
+ 5%
+
+
+ 工作量
+ 50%
+
+
+ 身体状态
+ 50%
+
+
+
+
+
颜色反转
+
+
+
+
+ 工资
+ 5%
+
+
+ 工作量
+ 50%
+
+
+
+
+
# AvatarList 组件
+
+
AvatarList
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# CountDown 组件
+
+
CountDown
+
+
+
+
+
+
+
+
+
+
+
# Ellipsis 组件
+
+
Ellipsis
+
+
+ There were injuries alleged in three cases in 2015, and a
+ fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.
+
+
+
+
# NumberInfo 组件
+
+
NumberInfo
+
+
+
+
+
# TagSelect 组件
+
+
TagSelect
+
+
+ 类目1
+ 类目2
+ 类目3
+ 类目4
+ 类目5
+ 类目6
+ 类目7
+
+
+
+
# DescriptionList 组件
+
+
DescriptionList
+
+
+ 林东东
+ 1234567
+ XX公司-YY部
+ 2018-08-08
+ 这段描述很长很长很长很长很长很长很长很长很长很长很长很长很长很长...
+
+
+
+
TagCloud
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/main/README.md b/_web/src/views/main/README.md
new file mode 100644
index 00000000..fadf99a4
--- /dev/null
+++ b/_web/src/views/main/README.md
@@ -0,0 +1 @@
+/** 您的业务接口文件全写在此文件夹下面,升级底座直接迁移代码即可 **/
diff --git a/_web/src/views/system/README.md b/_web/src/views/system/README.md
new file mode 100644
index 00000000..46aab4d5
--- /dev/null
+++ b/_web/src/views/system/README.md
@@ -0,0 +1 @@
+/** 此文件夹下代码尽量不要动,底座升级直接覆盖替换 **/
diff --git a/_web/src/views/system/account/center/Index.vue b/_web/src/views/system/account/center/Index.vue
new file mode 100644
index 00000000..bb1a1cdc
--- /dev/null
+++ b/_web/src/views/system/account/center/Index.vue
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
+
{{ nickname() }}
+
海纳百川,有容乃大
+
+
+
+ 交互专家
+
+
+ 蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED
+
+
+
+ 浙江省
+ 杭州市
+
+
+
+
+
+
+
+
+
+
+
+ handleTabChange(key, 'noTitleKey')"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/center/page/App.vue b/_web/src/views/system/account/center/page/App.vue
new file mode 100644
index 00000000..853aeab7
--- /dev/null
+++ b/_web/src/views/system/account/center/page/App.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/center/page/Article.vue b/_web/src/views/system/account/center/page/Article.vue
new file mode 100644
index 00000000..a53d23ca
--- /dev/null
+++ b/_web/src/views/system/account/center/page/Article.vue
@@ -0,0 +1,63 @@
+
+
+
+
+ {{ item.title }}
+
+
+ Ant Design
+ 设计语言
+ 蚂蚁金服
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/center/page/Project.vue b/_web/src/views/system/account/center/page/Project.vue
new file mode 100644
index 00000000..145232fb
--- /dev/null
+++ b/_web/src/views/system/account/center/page/Project.vue
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+ {{ item.description }}
+
+
+
+
{{ item.updatedAt | fromNow }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/center/page/index.js b/_web/src/views/system/account/center/page/index.js
new file mode 100644
index 00000000..b579b6a3
--- /dev/null
+++ b/_web/src/views/system/account/center/page/index.js
@@ -0,0 +1,5 @@
+import AppPage from './App'
+import ArticlePage from './Article'
+import ProjectPage from './Project'
+
+export { AppPage, ArticlePage, ProjectPage }
diff --git a/_web/src/views/system/account/settings/AvatarModal.vue b/_web/src/views/system/account/settings/AvatarModal.vue
new file mode 100644
index 00000000..289c9d03
--- /dev/null
+++ b/_web/src/views/system/account/settings/AvatarModal.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/settings/BaseSetting.vue b/_web/src/views/system/account/settings/BaseSetting.vue
new file mode 100644
index 00000000..c7b11cf2
--- /dev/null
+++ b/_web/src/views/system/account/settings/BaseSetting.vue
@@ -0,0 +1,216 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 更新基本信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/settings/Binding.vue b/_web/src/views/system/account/settings/Binding.vue
new file mode 100644
index 00000000..cbea7fc0
--- /dev/null
+++ b/_web/src/views/system/account/settings/Binding.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/settings/Custom.vue b/_web/src/views/system/account/settings/Custom.vue
new file mode 100644
index 00000000..c235570f
--- /dev/null
+++ b/_web/src/views/system/account/settings/Custom.vue
@@ -0,0 +1,75 @@
+
+
+
diff --git a/_web/src/views/system/account/settings/Index.vue b/_web/src/views/system/account/settings/Index.vue
new file mode 100644
index 00000000..8db2efb6
--- /dev/null
+++ b/_web/src/views/system/account/settings/Index.vue
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/settings/Notification.vue b/_web/src/views/system/account/settings/Notification.vue
new file mode 100644
index 00000000..cbea7fc0
--- /dev/null
+++ b/_web/src/views/system/account/settings/Notification.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/settings/Security.vue b/_web/src/views/system/account/settings/Security.vue
new file mode 100644
index 00000000..2d3b6509
--- /dev/null
+++ b/_web/src/views/system/account/settings/Security.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/account/settings/securityItem/updPwd.vue b/_web/src/views/system/account/settings/securityItem/updPwd.vue
new file mode 100644
index 00000000..a3bbcb17
--- /dev/null
+++ b/_web/src/views/system/account/settings/securityItem/updPwd.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/app/addForm.vue b/_web/src/views/system/app/addForm.vue
new file mode 100644
index 00000000..513f0305
--- /dev/null
+++ b/_web/src/views/system/app/addForm.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/app/editForm.vue b/_web/src/views/system/app/editForm.vue
new file mode 100644
index 00000000..e36a7037
--- /dev/null
+++ b/_web/src/views/system/app/editForm.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/app/index.vue b/_web/src/views/system/app/index.vue
new file mode 100644
index 00000000..2efcd458
--- /dev/null
+++ b/_web/src/views/system/app/index.vue
@@ -0,0 +1,218 @@
+/* eslint-disable eqeqeq */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+ {{ activeFilter(text) }}
+
+
+ {{ statusFilter(text) }}
+
+
+
+ 编辑
+
+ sysAppDelete(record)">
+ 删除
+
+
+
+
+ sysDefault(record)">
+ 设为默认
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/config/addForm.vue b/_web/src/views/system/config/addForm.vue
new file mode 100644
index 00000000..9ca74ab3
--- /dev/null
+++ b/_web/src/views/system/config/addForm.vue
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 是
+ 否
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/config/editForm.vue b/_web/src/views/system/config/editForm.vue
new file mode 100644
index 00000000..fcb91dc8
--- /dev/null
+++ b/_web/src/views/system/config/editForm.vue
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 是
+ 否
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/config/index.vue b/_web/src/views/system/config/index.vue
new file mode 100644
index 00000000..624d9386
--- /dev/null
+++ b/_web/src/views/system/config/index.vue
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ groupCodeFilter(text) }}
+
+
+ 编辑
+
+ sysConfigDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dashboard/Analysis.vue b/_web/src/views/system/dashboard/Analysis.vue
new file mode 100644
index 00000000..6df9244d
--- /dev/null
+++ b/_web/src/views/system/dashboard/Analysis.vue
@@ -0,0 +1,407 @@
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dashboard/Monitor.vue b/_web/src/views/system/dashboard/Monitor.vue
new file mode 100644
index 00000000..2b9c6c1c
--- /dev/null
+++ b/_web/src/views/system/dashboard/Monitor.vue
@@ -0,0 +1,15 @@
+
+
+ Monitor
+
+
+
+
+
+
diff --git a/_web/src/views/system/dashboard/TestWork.vue b/_web/src/views/system/dashboard/TestWork.vue
new file mode 100644
index 00000000..ae80f932
--- /dev/null
+++ b/_web/src/views/system/dashboard/TestWork.vue
@@ -0,0 +1,117 @@
+
+
+
本页面内容均为测试功能,暂不提供稳定性保证
+
+
+
多标签组件测试功能
+
关闭当前页
+
打开 任务列表
+
+
+
+
+ visible = !visible" style="margin-right: 16px;">修改当前 Tab 名称
+
+
+
visible2 = false" okText="确定" cancelText="取消">
+
+
+
页面 KEY 是由页面的路由 path
决定的
+
如果要修改某一个页面标题,该页面必须已经被打开在 Tab 栏
+
后期可以考虑优化到编程式 Tab 栏,就可以没有这种限制
+
+
+
+
+
+
+
+
+
+
+ visible2 = !visible2">修改某一个 Tab 名称
+
+
+
+
+
全局遮罩测试
+
打开遮罩(5s 自动关闭)
+
打开遮罩(自定义提示语)
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dashboard/Workplace.vue b/_web/src/views/system/dashboard/Workplace.vue
new file mode 100644
index 00000000..b0770b72
--- /dev/null
+++ b/_web/src/views/system/dashboard/Workplace.vue
@@ -0,0 +1,526 @@
+
+
+
+
{{ timeFix }},{{ user.name }},{{ welcome }}
+
前端工程师 | 蚂蚁金服 - 某某某事业群 - VUE平台
+
+
+
+
+
+
+
+ 全部项目
+
+
+
+
+
+
+ {{ item.description }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.time }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dict/addForm.vue b/_web/src/views/system/dict/addForm.vue
new file mode 100644
index 00000000..94dad704
--- /dev/null
+++ b/_web/src/views/system/dict/addForm.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dict/dictdata/addForm.vue b/_web/src/views/system/dict/dictdata/addForm.vue
new file mode 100644
index 00000000..2dce343c
--- /dev/null
+++ b/_web/src/views/system/dict/dictdata/addForm.vue
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dict/dictdata/editForm.vue b/_web/src/views/system/dict/dictdata/editForm.vue
new file mode 100644
index 00000000..a6bfeb1d
--- /dev/null
+++ b/_web/src/views/system/dict/dictdata/editForm.vue
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dict/dictdata/index.vue b/_web/src/views/system/dict/dictdata/index.vue
new file mode 100644
index 00000000..ebac8bef
--- /dev/null
+++ b/_web/src/views/system/dict/dictdata/index.vue
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+ {{ statusFilter(text) }}
+
+
+ 编辑
+
+ sysDictDataDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dict/editForm.vue b/_web/src/views/system/dict/editForm.vue
new file mode 100644
index 00000000..49ee823c
--- /dev/null
+++ b/_web/src/views/system/dict/editForm.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/dict/index.vue b/_web/src/views/system/dict/index.vue
new file mode 100644
index 00000000..77b0d827
--- /dev/null
+++ b/_web/src/views/system/dict/index.vue
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+
+
+ {{ statusFilter(text) }}
+
+
+
+ 字典
+
+
+
+ 更多
+
+
+
+
+ 编辑
+
+
+
+ sysDictTypeDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/email/index.vue b/_web/src/views/system/email/index.vue
new file mode 100644
index 00000000..73f33092
--- /dev/null
+++ b/_web/src/views/system/email/index.vue
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 发送
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 发送
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/exception/403.vue b/_web/src/views/system/exception/403.vue
new file mode 100644
index 00000000..ffc3799c
--- /dev/null
+++ b/_web/src/views/system/exception/403.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/exception/404.vue b/_web/src/views/system/exception/404.vue
new file mode 100644
index 00000000..16f767f4
--- /dev/null
+++ b/_web/src/views/system/exception/404.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/exception/500.vue b/_web/src/views/system/exception/500.vue
new file mode 100644
index 00000000..cc5d7ab1
--- /dev/null
+++ b/_web/src/views/system/exception/500.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/file/detailForm.vue b/_web/src/views/system/file/detailForm.vue
new file mode 100644
index 00000000..f25b7197
--- /dev/null
+++ b/_web/src/views/system/file/detailForm.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+ {{ fileDetail.fileLocation }}
+
+
+ {{ fileDetail.fileBucket }}
+
+
+ {{ fileDetail.fileOriginName }}
+
+
+ {{ fileDetail.fileSuffix }}
+
+
+ {{ fileDetail.fileSizeKb }}
+
+
+ {{ fileDetail.fileObjectName }}
+
+
+
+ {{ fileDetail.filePath }}
+
+
+
+
+
+
diff --git a/_web/src/views/system/file/index.vue b/_web/src/views/system/file/index.vue
new file mode 100644
index 00000000..2673c04c
--- /dev/null
+++ b/_web/src/views/system/file/index.vue
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ fileLocationFilter(text) }}
+
+
+ {{ text }}
+
+
+ 下载
+
+ 详情
+
+ sysFileInfoDelete(record)">
+ 删除
+
+
+ 预览
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/file/previewForm.vue b/_web/src/views/system/file/previewForm.vue
new file mode 100644
index 00000000..f125b93c
--- /dev/null
+++ b/_web/src/views/system/file/previewForm.vue
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/index/welcome.vue b/_web/src/views/system/index/welcome.vue
new file mode 100644
index 00000000..a5c75754
--- /dev/null
+++ b/_web/src/views/system/index/welcome.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/log/oplog/details.vue b/_web/src/views/system/log/oplog/details.vue
new file mode 100644
index 00000000..c7ddd8df
--- /dev/null
+++ b/_web/src/views/system/log/oplog/details.vue
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/log/oplog/index.vue b/_web/src/views/system/log/oplog/index.vue
new file mode 100644
index 00000000..a00f1b0a
--- /dev/null
+++ b/_web/src/views/system/log/oplog/index.vue
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
sysOpLogDelete()">
+ 清空日志
+
+
+
+
+ {{ opTypeFilter(text) }}
+
+
+ {{ successFilter(text) }}
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+
+ 查看详情
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/log/vislog/details.vue b/_web/src/views/system/log/vislog/details.vue
new file mode 100644
index 00000000..697c7d8f
--- /dev/null
+++ b/_web/src/views/system/log/vislog/details.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/log/vislog/index.vue b/_web/src/views/system/log/vislog/index.vue
new file mode 100644
index 00000000..fba9d8ff
--- /dev/null
+++ b/_web/src/views/system/log/vislog/index.vue
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
sysVisLogDelete()">
+ 清空日志
+
+
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ visTypeFilter(text) }}
+
+
+ {{ successFilter(text) }}
+
+
+
+ 查看详情
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/machine/index.vue b/_web/src/views/system/machine/index.vue
new file mode 100644
index 00000000..0500b2d4
--- /dev/null
+++ b/_web/src/views/system/machine/index.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+ 系统名称:
+ {{ this.sysOsInfo.osName }}
+
+
+
+ 系统架构:
+ {{ this.sysOsInfo.osArch }}
+
+
+
+ 系统版本:
+ {{ this.sysOsInfo.osVersion }}
+
+
+
+ 主机名称:
+ {{ this.sysOsInfo.osHostName }}
+
+
+
+ 主机IP地址:
+ {{ this.sysOsInfo.osHostAddress }}
+
+
+
+
+
+
+
+
+
+
+ 虚拟机名称:
+ {{ this.sysJavaInfo.jvmName }}
+
+
+
+ 虚拟机版本:
+ {{ this.sysJavaInfo.jvmVersion }}
+
+
+
+ 虚拟机供应商:
+ {{ this.sysJavaInfo.jvmVendor }}
+
+
+
+ java名称:
+ {{ this.sysJavaInfo.javaName }}
+
+
+
+ java版本:
+ {{ this.sysJavaInfo.javaVersion }}
+
+
+
+
+
+
+
+
+
+
+ 最大内存:
+ {{ this.sysJvmMemInfo.jvmMaxMemory }}
+ 可用内存:
+ {{ this.sysJvmMemInfo.jvmUsableMemory }}
+
+
+ 总内存:
+ {{ this.sysJvmMemInfo.jvmTotalMemory }}
+ 已使用内存:
+ {{ this.sysJvmMemInfo.jvmUsedMemory }}
+
+
+ 空余内存:
+ {{ this.sysJvmMemInfo.jvmFreeMemory }}
+ 使用率:
+ {{ this.sysJvmMemInfo.jvmMemoryUsedRate }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/menu/addForm.vue b/_web/src/views/system/menu/addForm.vue
new file mode 100644
index 00000000..30cad95b
--- /dev/null
+++ b/_web/src/views/system/menu/addForm.vue
@@ -0,0 +1,567 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 打开方式
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 内外链地址
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 权重
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/menu/editForm.vue b/_web/src/views/system/menu/editForm.vue
new file mode 100644
index 00000000..714b24ee
--- /dev/null
+++ b/_web/src/views/system/menu/editForm.vue
@@ -0,0 +1,627 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 打开方式
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 内外链地址
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 权重
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/menu/index.vue b/_web/src/views/system/menu/index.vue
new file mode 100644
index 00000000..db91301b
--- /dev/null
+++ b/_web/src/views/system/menu/index.vue
@@ -0,0 +1,188 @@
+/* eslint-disable */
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ typeFilter(text) }}
+
+
+
+
+
+
+
+
+ 编辑
+
+ handleDel(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/notice/addForm.vue b/_web/src/views/system/notice/addForm.vue
new file mode 100644
index 00000000..e6e41ea3
--- /dev/null
+++ b/_web/src/views/system/notice/addForm.vue
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+ 发布
+ 存为草稿
+ 取消
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/notice/detailForm.vue b/_web/src/views/system/notice/detailForm.vue
new file mode 100644
index 00000000..dc837b06
--- /dev/null
+++ b/_web/src/views/system/notice/detailForm.vue
@@ -0,0 +1,60 @@
+
+
+
+ {{ this.contentRecord.title }}
+
+
+ (发布人:{{ this.contentRecord.publicUserName }})
+ 发布时间:{{ this.contentRecord.publicTime }}
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/notice/editForm.vue b/_web/src/views/system/notice/editForm.vue
new file mode 100644
index 00000000..604df460
--- /dev/null
+++ b/_web/src/views/system/notice/editForm.vue
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+ 发布
+ 存为草稿
+ 取消
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/notice/index.vue b/_web/src/views/system/notice/index.vue
new file mode 100644
index 00000000..bd823ca6
--- /dev/null
+++ b/_web/src/views/system/notice/index.vue
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+ {{ statusFilter(text) }}
+
+
+ {{ typeFilter(text) }}
+
+
+
+
查看
+
+
编辑
+
+
editNoticeStatus(1,record)">
+ 发布
+
+
+
+
查看
+
+
editNoticeStatus(2,record)">
+ 撤回
+
+
+
+
查看
+
+
sysNoticeDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/noticeReceived/detailForm.vue b/_web/src/views/system/noticeReceived/detailForm.vue
new file mode 100644
index 00000000..00340ce4
--- /dev/null
+++ b/_web/src/views/system/noticeReceived/detailForm.vue
@@ -0,0 +1,75 @@
+
+
+
+
+ {{ this.contentRecord.title }}
+
+
+ (发布人:{{ this.contentRecord.publicUserName }})
+ 发布时间:{{ this.contentRecord.publicTime }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/noticeReceived/index.vue b/_web/src/views/system/noticeReceived/index.vue
new file mode 100644
index 00000000..a99bc553
--- /dev/null
+++ b/_web/src/views/system/noticeReceived/index.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+
+
+ {{ statusFilter(text) }}
+
+
+
+ {{ typeFilter(text) }}
+
+
+
+ 查看
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/onlineUser/index.vue b/_web/src/views/system/onlineUser/index.vue
new file mode 100644
index 00000000..c3c33621
--- /dev/null
+++ b/_web/src/views/system/onlineUser/index.vue
@@ -0,0 +1,127 @@
+
+
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ forceExist(record)">
+ 强制下线
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/org/addForm.vue b/_web/src/views/system/org/addForm.vue
new file mode 100644
index 00000000..f037dc1b
--- /dev/null
+++ b/_web/src/views/system/org/addForm.vue
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ id }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/org/editForm.vue b/_web/src/views/system/org/editForm.vue
new file mode 100644
index 00000000..029d4e1f
--- /dev/null
+++ b/_web/src/views/system/org/editForm.vue
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ id }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/org/index.vue b/_web/src/views/system/org/index.vue
new file mode 100644
index 00000000..998eeae4
--- /dev/null
+++ b/_web/src/views/system/org/index.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+ sysOrgDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/pos/addForm.vue b/_web/src/views/system/pos/addForm.vue
new file mode 100644
index 00000000..765eb756
--- /dev/null
+++ b/_web/src/views/system/pos/addForm.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/pos/editForm.vue b/_web/src/views/system/pos/editForm.vue
new file mode 100644
index 00000000..2fe56718
--- /dev/null
+++ b/_web/src/views/system/pos/editForm.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/pos/index.vue b/_web/src/views/system/pos/index.vue
new file mode 100644
index 00000000..4d3b8f60
--- /dev/null
+++ b/_web/src/views/system/pos/index.vue
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+ sysPosDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/role/addForm.vue b/_web/src/views/system/role/addForm.vue
new file mode 100644
index 00000000..faa9f10e
--- /dev/null
+++ b/_web/src/views/system/role/addForm.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/role/editForm.vue b/_web/src/views/system/role/editForm.vue
new file mode 100644
index 00000000..58513f93
--- /dev/null
+++ b/_web/src/views/system/role/editForm.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/role/index.vue b/_web/src/views/system/role/index.vue
new file mode 100644
index 00000000..37a9b0df
--- /dev/null
+++ b/_web/src/views/system/role/index.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+
+ 更多
+
+
+
+ 授权菜单
+
+
+ 授权数据
+
+
+ sysRoleDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/role/roleMenuForm.vue b/_web/src/views/system/role/roleMenuForm.vue
new file mode 100644
index 00000000..bdcacd66
--- /dev/null
+++ b/_web/src/views/system/role/roleMenuForm.vue
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/role/roleOrgForm.vue b/_web/src/views/system/role/roleOrgForm.vue
new file mode 100644
index 00000000..61f6235c
--- /dev/null
+++ b/_web/src/views/system/role/roleOrgForm.vue
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/sms/index.vue b/_web/src/views/system/sms/index.vue
new file mode 100644
index 00000000..04d6d82d
--- /dev/null
+++ b/_web/src/views/system/sms/index.vue
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+ {{ statusFilter(text) }}
+
+
+ {{ sourceFilter(text) }}
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/timers/addForm.vue b/_web/src/views/system/timers/addForm.vue
new file mode 100644
index 00000000..9927aa5c
--- /dev/null
+++ b/_web/src/views/system/timers/addForm.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/timers/editForm.vue b/_web/src/views/system/timers/editForm.vue
new file mode 100644
index 00000000..ea8ef52e
--- /dev/null
+++ b/_web/src/views/system/timers/editForm.vue
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/timers/index.vue b/_web/src/views/system/timers/index.vue
new file mode 100644
index 00000000..e177bc93
--- /dev/null
+++ b/_web/src/views/system/timers/index.vue
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ editjobStatusStatus(text,record)">
+
+ {{ jobStatusFilter(text) }}
+
+
+
+
+ {{ jobStatusFilter(text) }}
+
+
+ 编辑
+
+ sysTimersDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/user/addForm.vue b/_web/src/views/system/user/addForm.vue
new file mode 100644
index 00000000..cb36da38
--- /dev/null
+++ b/_web/src/views/system/user/addForm.vue
@@ -0,0 +1,467 @@
+
+
+
+ 基本信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 男
+ 女
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 员工信息
+
+
+
+
+ initrOrgName(e)"
+ >
+ {{ id }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+
+
+ handleChange(e,record.key,col)"
+ >
+ {{ id }}
+
+
+ {{ record.extOrgName }}
+
+
+ handleChange(e,record.key,col)"
+ has-feedback
+ >
+ {{ item.name }}
+
+ {{ record.extPosName }}
+
+
+
+ 删除
+
+
+ 增行
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/user/editForm.vue b/_web/src/views/system/user/editForm.vue
new file mode 100644
index 00000000..a204c5db
--- /dev/null
+++ b/_web/src/views/system/user/editForm.vue
@@ -0,0 +1,493 @@
+/* eslint-disable vue/no-template-shadow */
+
+
+
+ 基本信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 男
+ 女
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 员工信息
+
+
+
+
+ initrOrgName(e)"
+ >
+ {{ id }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+ handleChange(e,record.key,col)"
+ >
+ {{ id }}
+
+
+
+ handleChange(e,record.key,col)"
+ >
+ {{ id }}
+
+
+
+
+
+ handleChange(e,record.key,col)"
+ has-feedback
+ >
+ // eslint-disable-next-line vue/no-template-shadow
+ {{ item.name }}
+
+
+
+ handleChange(e,record.key,col)"
+ has-feedback
+ >
+ // eslint-disable-next-line vue/no-template-shadow
+ {{ item.name }}
+
+
+
+
+
+ 删除
+
+
+ 增行
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/user/index.vue b/_web/src/views/system/user/index.vue
new file mode 100644
index 00000000..0606b278
--- /dev/null
+++ b/_web/src/views/system/user/index.vue
@@ -0,0 +1,328 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.value }}
+
+
+
+
+ 查询
+ queryParam = {}">重置
+
+
+
+
+
+
+
+
+
+ {{ sexFilter(text) }}
+
+
+
+ editUserStatus(text,record)">
+ {{ statusFilter(text) }}
+
+
+
+ {{ statusFilter(text) }}
+
+
+
+ 编辑
+
+
+
+ 更多
+
+
+
+ resetPwd(record)">
+ 重置密码
+
+
+
+ 授权角色
+
+
+ 授权数据
+
+
+ sysUserDelete(record)">
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/user/userOrgForm.vue b/_web/src/views/system/user/userOrgForm.vue
new file mode 100644
index 00000000..8c839dc7
--- /dev/null
+++ b/_web/src/views/system/user/userOrgForm.vue
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/system/user/userRoleForm.vue b/_web/src/views/system/user/userRoleForm.vue
new file mode 100644
index 00000000..8aaf363f
--- /dev/null
+++ b/_web/src/views/system/user/userRoleForm.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/userLoginReg/Login.vue b/_web/src/views/userLoginReg/Login.vue
new file mode 100644
index 00000000..1ceec988
--- /dev/null
+++ b/_web/src/views/userLoginReg/Login.vue
@@ -0,0 +1,311 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 自动登录
+ 忘记密码
+
+
+
+ 确定
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/userLoginReg/Register.vue b/_web/src/views/userLoginReg/Register.vue
new file mode 100644
index 00000000..2b202649
--- /dev/null
+++ b/_web/src/views/userLoginReg/Register.vue
@@ -0,0 +1,322 @@
+
+
+
注册
+
+
+
+
+
+
+
+
+
强度:{{ passwordLevelName }}
+
+
+ 请至少输入 6 个字符。请不要使用容易被猜到的密码。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +86
+ +87
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 注册
+
+ 使用已有账户登录
+
+
+
+
+
+
+
+
+
diff --git a/_web/src/views/userLoginReg/RegisterResult.vue b/_web/src/views/userLoginReg/RegisterResult.vue
new file mode 100644
index 00000000..5a807e08
--- /dev/null
+++ b/_web/src/views/userLoginReg/RegisterResult.vue
@@ -0,0 +1,50 @@
+
+
+
+
+ 查看邮箱
+ 返回首页
+
+
+
+
+
+
+
+
diff --git a/_web/tests/unit/.eslintrc.js b/_web/tests/unit/.eslintrc.js
new file mode 100644
index 00000000..958d51ba
--- /dev/null
+++ b/_web/tests/unit/.eslintrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+ env: {
+ jest: true
+ }
+}
diff --git a/_web/vue.config.js b/_web/vue.config.js
new file mode 100644
index 00000000..0bd9a55d
--- /dev/null
+++ b/_web/vue.config.js
@@ -0,0 +1,114 @@
+const path = require('path')
+const webpack = require('webpack')
+const createThemeColorReplacerPlugin = require('./config/plugin.config')
+
+function resolve (dir) {
+ return path.join(__dirname, dir)
+}
+
+const isProd = process.env.NODE_ENV === 'production'
+
+const assetsCDN = {
+ // webpack build externals
+ externals: {
+ vue: 'Vue',
+ 'vue-router': 'VueRouter',
+ vuex: 'Vuex',
+ axios: 'axios'
+ },
+ css: [],
+ // https://unpkg.com/browse/vue@2.6.10/
+ js: [
+ '//cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js',
+ '//cdn.jsdelivr.net/npm/vue-router@3.1.3/dist/vue-router.min.js',
+ '//cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js',
+ '//cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js'
+ ]
+}
+
+// vue.config.js
+const vueConfig = {
+ configureWebpack: {
+ // webpack plugins
+ plugins: [
+ // Ignore all locale files of moment.js
+ new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
+ ],
+ // if prod, add externals
+ externals: isProd ? assetsCDN.externals : {}
+ },
+
+ chainWebpack: (config) => {
+ config.resolve.alias
+ .set('@$', resolve('src'))
+
+ const svgRule = config.module.rule('svg')
+ svgRule.uses.clear()
+ svgRule
+ .oneOf('inline')
+ .resourceQuery(/inline/)
+ .use('vue-svg-icon-loader')
+ .loader('vue-svg-icon-loader')
+ .end()
+ .end()
+ .oneOf('external')
+ .use('file-loader')
+ .loader('file-loader')
+ .options({
+ name: 'assets/[name].[hash:8].[ext]'
+ })
+
+ // if prod is on
+ // assets require on cdn
+ if (isProd) {
+ config.plugin('html').tap(args => {
+ args[0].cdn = assetsCDN
+ return args
+ })
+ }
+ },
+
+ css: {
+ loaderOptions: {
+ less: {
+ modifyVars: {
+ 'primary-color': '#1890FF',
+ 'layout-color': '#1890FF',
+ 'border-radius-base': '2px'
+ },
+ // DO NOT REMOVE THIS LINE
+ javascriptEnabled: true
+ }
+ }
+ },
+
+ devServer: {
+ port: 81,
+ proxy: {
+ '/api': {
+ target: process.env.VUE_APP_API_BASE_URL,
+ ws: false,
+ changeOrigin: true,
+ pathRewrite: {
+ '^/api': '' // 需要rewrite的,
+ }
+ }
+ }
+ },
+
+ // disable source map in production
+ productionSourceMap: false,
+ lintOnSave: undefined,
+ // babel-loader no-ignore node_modules/*
+ transpileDependencies: []
+}
+
+// preview.pro.loacg.com only do not use in your production;
+if (process.env.VUE_APP_PREVIEW === 'true') {
+ // eslint-disable-next-line no-labels
+ // runtimeCompiler: true,
+ // add `ThemeColorReplacer` plugin to webpack plugins
+ vueConfig.configureWebpack.plugins.push(createThemeColorReplacerPlugin())
+}
+
+module.exports = vueConfig
diff --git a/_web/webstorm.config.js b/_web/webstorm.config.js
new file mode 100644
index 00000000..91174556
--- /dev/null
+++ b/_web/webstorm.config.js
@@ -0,0 +1,3 @@
+'use strict'
+const webpackConfig = require('@vue/cli-service/webpack.config.js')
+module.exports = webpackConfig
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..9adab4d7
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,256 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.3.1.RELEASE
+
+
+ cn.xiaonuo
+ xiaonuo-vue
+ 1.1.0
+
+ xiaonuo-vue
+ xiaonuo-vue版本
+
+ pom
+
+
+ xiaonuo-base
+ xiaonuo-main
+
+
+
+ UTF-8
+ UTF-8
+ 8.0.17
+ 1.1.21
+ 3.3.2
+ 1.2.70
+ 0.9.1
+ 5.3.7
+ 1.18.12
+ 2.9.2
+ 1.9.6
+ 4.2.0
+ 4.2.0
+ 6.4.3
+ 1.15.6
+ 3.8.0
+ 5.6.23
+ 4.4.6
+ 4.17.6
+ 3.1.57
+
+
+
+
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ ${mp.version}
+
+
+
+
+ mysql
+ mysql-connector-java
+ ${mysql-connector-java.version}
+
+
+
+
+ com.alibaba
+ druid
+ ${druid.version}
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+ ${jwt.version}
+
+
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+
+ cn.hutool
+ hutool-all
+ ${hutool.version}
+
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.versin}
+
+
+
+
+ io.springfox
+ springfox-swagger2
+ ${swagger.version}
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger.version}
+
+
+ com.github.xiaoymin
+ swagger-bootstrap-ui
+ ${swagger.bootstrap.ui.version}
+
+
+
+
+ cn.afterturn
+ easypoi-base
+ ${easypoi.version}
+
+
+
+
+ org.jodconverter
+ jodconverter-core
+ ${jodconverter.version}
+
+
+ org.jodconverter
+ jodconverter-local
+ ${jodconverter.version}
+
+
+ org.jodconverter
+ jodconverter-spring-boot-starter
+ ${jodconverter.version}
+
+
+ org.libreoffice
+ ridl
+ ${libreoffice.version}
+
+
+
+
+ me.zhyd.oauth
+ JustAuth
+ ${justauth.version}
+
+
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+ ${aliyun.oss.version}
+
+
+
+
+ com.qcloud
+ cos_api
+ ${qcloud.oss.version}
+
+
+
+
+ com.aliyun
+ aliyun-java-sdk-core
+ ${aliyun.sms.sdk.version}
+
+
+ com.aliyun
+ aliyun-java-sdk-ecs
+ ${aliyun.sms.esc.version}
+
+
+
+
+ com.tencentcloudapi
+ tencentcloud-sdk-java
+ ${qcloud.sms.sdk.version}
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ @
+
+ false
+
+
+
+
+
+ src/main/webapp
+ false
+
+
+ src/main/resources
+ true
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
+
+
+ local
+
+ local
+
+
+ true
+
+
+
+ dev
+
+ dev
+
+
+
+ prod
+
+ prod
+
+
+
+
+
diff --git a/xiaonuo-base/README.md b/xiaonuo-base/README.md
new file mode 100644
index 00000000..e47621ab
--- /dev/null
+++ b/xiaonuo-base/README.md
@@ -0,0 +1 @@
+** 此模块大家尽量不要动,升级的时候只要将XiaoNuo的包覆盖此模块即可 **
diff --git a/xiaonuo-base/pom.xml b/xiaonuo-base/pom.xml
new file mode 100644
index 00000000..74a1749b
--- /dev/null
+++ b/xiaonuo-base/pom.xml
@@ -0,0 +1,23 @@
+
+
+ 4.0.0
+
+
+ cn.xiaonuo
+ xiaonuo-vue
+ 1.1.0
+ ../pom.xml
+
+
+ xiaonuo-base
+
+ pom
+
+
+ xiaonuo-core
+ xiaonuo-system
+
+
+
diff --git a/xiaonuo-base/xiaonuo-core/README.md b/xiaonuo-base/xiaonuo-core/README.md
new file mode 100644
index 00000000..10004527
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/README.md
@@ -0,0 +1,3 @@
+** 本模块是其他模块都会引用的模块,存放一些通用的工具类,枚举类,实体等 **
+
+** 工具类能用hutool的用hutool不要自己封装 **
\ No newline at end of file
diff --git a/xiaonuo-base/xiaonuo-core/pom.xml b/xiaonuo-base/xiaonuo-core/pom.xml
new file mode 100644
index 00000000..7a80434c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/pom.xml
@@ -0,0 +1,142 @@
+
+
+ 4.0.0
+
+
+ cn.xiaonuo
+ xiaonuo-base
+ 1.1.0
+ ../pom.xml
+
+
+ xiaonuo-core
+
+ jar
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+ com.alibaba
+ druid
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+
+
+ cn.hutool
+ hutool-all
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ com.alibaba
+ fastjson
+
+
+
+
+ cn.afterturn
+ easypoi-base
+
+
+
+
+ org.jodconverter
+ jodconverter-core
+
+
+ org.jodconverter
+ jodconverter-local
+
+
+ org.jodconverter
+ jodconverter-spring-boot-starter
+
+
+ org.libreoffice
+ ridl
+
+
+
+
+ me.zhyd.oauth
+ JustAuth
+
+
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+
+
+
+
+ com.qcloud
+ cos_api
+
+
+
+
+ com.aliyun
+ aliyun-java-sdk-core
+
+
+ com.aliyun
+ aliyun-java-sdk-ecs
+
+
+
+
+ com.tencentcloudapi
+ tencentcloud-sdk-java
+
+
+
+
+ ${project.artifactId}
+
+
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/BusinessLog.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/BusinessLog.java
new file mode 100644
index 00000000..b1dafeeb
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/BusinessLog.java
@@ -0,0 +1,51 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.annotion;
+
+import com.cn.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
+
+import java.lang.annotation.*;
+
+/**
+ * 标记需要做业务日志的方法
+ *
+ * @author yubaoshan
+ * @date 2017/3/31 12:46
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface BusinessLog {
+
+ /**
+ * 业务的名称,例如:"修改菜单"
+ */
+ String title() default "";
+
+ /**
+ * 业务操作类型枚举
+ */
+ LogAnnotionOpTypeEnum opType() default LogAnnotionOpTypeEnum.OTHER;
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/DataScope.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/DataScope.java
new file mode 100644
index 00000000..3a8bd667
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/DataScope.java
@@ -0,0 +1,39 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.annotion;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据权限注解
+ *
+ * @author xuyuxiang
+ * @date 2020/3/28 17:16
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface DataScope {
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/ExpEnumType.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/ExpEnumType.java
new file mode 100644
index 00000000..464b70aa
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/ExpEnumType.java
@@ -0,0 +1,56 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.annotion;
+
+import java.lang.annotation.*;
+
+/**
+ * 标识在ExceptionEnum类上,用来标识类级别异常枚举编码
+ *
+ * 异常枚举编码由3部分组成,如下:
+ *
+ * 模块编码(2位) + 分类编码(4位) + 具体项编码(至少1位)
+ *
+ * 模块编码和分类编码在ExpEnumCodeConstant类中声明
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 20:46
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface ExpEnumType {
+
+ /**
+ * 模块编码
+ */
+ int module() default 99;
+
+ /**
+ * 分类编码
+ */
+ int kind() default 9999;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/Permission.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/Permission.java
new file mode 100644
index 00000000..46e05ad1
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/Permission.java
@@ -0,0 +1,53 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.annotion;
+
+import com.cn.xiaonuo.core.enums.LogicTypeEnum;
+import com.cn.xiaonuo.core.enums.LogicTypeEnum;
+
+import java.lang.annotation.*;
+
+/**
+ * 权限注解,用于检查权限
+ * 使用方式:@Permission表示检查是否有权限访问该资源
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 14:44
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Permission {
+
+ /**
+ * 加上此注解表示需要有该资源url的才可以访问, 默认值为空,即该url,如果设置了值,则表示有该角色才可以访问
+ */
+ String[] value() default {};
+
+ /**
+ * 逻辑枚举,默认或
+ */
+ LogicTypeEnum logicType() default LogicTypeEnum.OR;
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/Wrapper.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/Wrapper.java
new file mode 100644
index 00000000..6e56dd40
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/annotion/Wrapper.java
@@ -0,0 +1,48 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.annotion;
+
+import com.cn.xiaonuo.core.pojo.base.wrapper.BaseWrapper;
+import com.cn.xiaonuo.core.pojo.base.wrapper.BaseWrapper;
+
+import java.lang.annotation.*;
+
+/**
+ * 结果包装的注解,一般用在Controller层,给最后响应结果做包装
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 17:10
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Wrapper {
+
+ /**
+ * 具体包装类
+ */
+ Class extends BaseWrapper>>[] value();
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/cache/CacheOperator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/cache/CacheOperator.java
new file mode 100644
index 00000000..2e1b275c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/cache/CacheOperator.java
@@ -0,0 +1,118 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.cache;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * 缓存操作的基础接口,可以实现不同种缓存实现
+ *
+ * 泛型为cache的值类class类型
+ *
+ * @author yubaoshan
+ * @date 2020/7/8 22:02
+ */
+public interface CacheOperator {
+
+ /**
+ * 添加缓存
+ *
+ * @param key 键
+ * @param value 值
+ * @author yubaoshan
+ * @date 2020/7/8 22:06
+ */
+ void put(String key, T value);
+
+ /**
+ * 添加缓存(带过期时间,单位是秒)
+ *
+ * @param key 键
+ * @param value 值
+ * @param timeoutSeconds 过期时间,单位秒
+ * @author yubaoshan
+ * @date 2020/7/8 22:07
+ */
+ void put(String key, T value, Long timeoutSeconds);
+
+ /**
+ * 通过缓存key获取缓存
+ *
+ * @param key 键
+ * @return 值
+ * @author yubaoshan
+ * @date 2020/7/8 22:08
+ */
+ Object get(String key);
+
+ /**
+ * 删除缓存
+ *
+ * @param key 键,多个
+ * @author yubaoshan
+ * @date 2020/7/8 22:09
+ */
+ void remove(String... key);
+
+ /**
+ * 获得缓存的所有key列表(不带common prefix的)
+ *
+ * @return key列表
+ * @author yubaoshan
+ * @date 2020/7/8 22:11
+ */
+ Collection getAllKeys();
+
+ /**
+ * 获得缓存的所有值列表
+ *
+ * @return 值列表
+ * @author yubaoshan
+ * @date 2020/7/8 22:11
+ */
+ Collection getAllValues();
+
+ /**
+ * 获取所有的key,value
+ *
+ * @return 键值map
+ * @author yubaoshan
+ * @date 2020/7/8 22:11
+ */
+ Map getAllKeyValues();
+
+ /**
+ * 通用缓存的前缀,用于区分不同业务
+ *
+ * 如果带了前缀,所有的缓存在添加的时候,key都会带上这个前缀
+ *
+ * @return 缓存前缀
+ * @author yubaoshan
+ * @date 2020/7/9 11:06
+ */
+ String getCommonKeyPrefix();
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/AopSortConstant.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/AopSortConstant.java
new file mode 100644
index 00000000..fe24e901
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/AopSortConstant.java
@@ -0,0 +1,72 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.consts;
+
+/**
+ * aop顺序的常量
+ *
+ * 顺序越小越靠前
+ *
+ * @author yubaoshan
+ * @date 2020/4/10 15:33
+ */
+public interface AopSortConstant {
+
+ /**
+ * 全局异常拦截器
+ */
+ int GLOBAL_EXP_HANDLER_AOP = -120;
+
+ /**
+ * 结果包装的aop
+ */
+ int WRAPPER_AOP = -110;
+
+ /**
+ * 接口资源权限校验
+ */
+ int PERMISSION_AOP = -100;
+
+ /**
+ * 数据范围AOP
+ */
+ int DATA_SCOPE_AOP = -50;
+
+ /**
+ * 多租户的aop
+ */
+ int TENANT_EXCHANGE_AOP = -10;
+
+ /**
+ * 多数据源切换的aop
+ */
+ int MULTI_DATA_SOURCE_AOP = 1;
+
+ /**
+ * 业务日志的AOP
+ */
+ int BUSINESS_LOG_AOP = 100;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/CommonConstant.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/CommonConstant.java
new file mode 100644
index 00000000..6a32b6da
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/CommonConstant.java
@@ -0,0 +1,109 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.consts;
+
+/**
+ * 通用常量
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 16:51
+ */
+public interface CommonConstant {
+
+ /**
+ * id
+ */
+ String ID = "id";
+
+ /**
+ * 名称
+ */
+ String NAME = "name";
+
+ /**
+ * 编码
+ */
+ String CODE = "code";
+
+ /**
+ * 值
+ */
+ String VALUE = "value";
+
+ /**
+ * 默认标识状态的字段名称
+ */
+ String STATUS = "status";
+
+ /**
+ * 默认逻辑删除的状态值
+ */
+ String DEFAULT_LOGIC_DELETE_VALUE = "2";
+
+ /**
+ * 用户代理
+ */
+ String USER_AGENT = "User-Agent";
+
+ /**
+ * 请求头token表示
+ */
+ String AUTHORIZATION = "Authorization";
+
+ /**
+ * token名称
+ */
+ String TOKEN_NAME = "token";
+
+ /**
+ * token类型
+ */
+ String TOKEN_TYPE_BEARER = "Bearer";
+
+ /**
+ * 首页提示语
+ */
+ String INDEX_TIPS = "Welcome To XiaoNuo";
+
+ /**
+ * 未知标识
+ */
+ String UNKNOWN = "Unknown";
+
+ /**
+ * 默认包名
+ */
+ String DEFAULT_PACKAGE_NAME = "com.cn.xiaonuo";
+
+ /**
+ * 默认密码
+ */
+ String DEFAULT_PASSWORD = "123456";
+
+ /**
+ * 请求号在header中的唯一标识
+ */
+ String REQUEST_NO_HEADER_NAME = "Request-No";
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/ExpEnumConstant.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/ExpEnumConstant.java
new file mode 100644
index 00000000..c116c516
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/ExpEnumConstant.java
@@ -0,0 +1,89 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.consts;
+
+/**
+ * 异常枚举编码构成常量
+ *
+ * 异常枚举编码由3部分组成,如下:
+ *
+ * 模块编码(2位) + 分类编码(4位) + 具体项编码(至少1位)
+ *
+ * 模块编码和分类编码在ExpEnumCodeConstant类中声明
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 20:46
+ */
+public interface ExpEnumConstant {
+
+ /**
+ * 模块分类编码(2位)
+ *
+ * xiaonuo-core模块异常枚举编码
+ */
+ int XIAONUO_CORE_MODULE_EXP_CODE = 10;
+
+ /* 分类编码(4位) */
+ /**
+ * 认证异常枚举
+ */
+ int AUTH_EXCEPTION_ENUM = 1100;
+
+ /**
+ * 参数校验异常枚举
+ */
+ int PARAM_EXCEPTION_ENUM = 1200;
+
+ /**
+ * 授权和鉴权异常的枚举
+ */
+ int PERMISSION_EXCEPTION_ENUM = 1300;
+
+ /**
+ * 请求方法相关异常枚举
+ */
+ int REQUEST_METHOD_EXCEPTION_ENUM = 1400;
+
+ /**
+ * 请求类型相关异常枚举
+ */
+ int REQUEST_TYPE_EXCEPTION_ENUM = 1500;
+
+ /**
+ * 服务器内部相关异常枚举
+ */
+ int SERVER_EXCEPTION_ENUM = 1600;
+
+ /**
+ * 状态相关异常枚举
+ */
+ int STATUS_EXCEPTION_ENUM = 1700;
+
+ /**
+ * 包装相关异常枚举
+ */
+ int WRAPPER_EXCEPTION_ENUM = 1800;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/MediaTypeConstant.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/MediaTypeConstant.java
new file mode 100644
index 00000000..f9287227
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/MediaTypeConstant.java
@@ -0,0 +1,99 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.consts;
+
+/**
+ * 常用媒体类型常量
+ *
+ * @author xuyuxiang
+ * @date 2020/7/9 14:14
+ */
+public interface MediaTypeConstant {
+
+ /**
+ * 图片jpg格式
+ */
+ String IMG_JPG = "jpg";
+
+ /**
+ * 图片png格式
+ */
+ String IMG_PNG = "png";
+
+ /**
+ * 图片jpeg格式
+ */
+ String IMG_JPEG = "jpeg";
+
+ /**
+ * 图片tif格式
+ */
+ String IMG_TIF = "tif";
+
+ /**
+ * 图片gif格式
+ */
+ String IMG_GIF = "gif";
+
+ /**
+ * 图片bmp格式
+ */
+ String IMG_BMP = "bmp";
+
+ /**
+ * 文档txt格式
+ */
+ String DOC_TXT = "txt";
+
+ /**
+ * 文档doc格式
+ */
+ String DOC_DOC = "doc";
+
+ /**
+ * 文档docx格式
+ */
+ String DOC_DOCX = "docx";
+
+ /**
+ * 文档xls格式
+ */
+ String DOC_XLS = "xls";
+
+ /**
+ * 文档xlsx格式
+ */
+ String DOC_XLSX = "xlsx";
+
+ /**
+ * 文档ppt格式
+ */
+ String DOC_PPT = "ppt";
+
+ /**
+ * 文档pptx格式
+ */
+ String DOC_PPTX = "pptx";
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/SpringSecurityConstant.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/SpringSecurityConstant.java
new file mode 100644
index 00000000..4f9a85c9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/SpringSecurityConstant.java
@@ -0,0 +1,68 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.consts;
+
+/**
+ * SpringSecurity相关常量
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 17:49
+ */
+public interface SpringSecurityConstant {
+
+ /**
+ * 放开权限校验的接口
+ */
+ String[] NONE_SECURITY_URL_PATTERNS = {
+
+ //前端的
+ "/favicon.ico",
+
+ //swagger相关的
+ "/doc.html",
+ "/webjars/**",
+ "/swagger-resources/**",
+ "/v2/api-docs",
+ "/v2/api-docs-ext",
+ "/configuration/ui",
+ "/configuration/security",
+
+ //后端的
+ "/",
+ "/login",
+ "/logout",
+ "/oauth/**",
+
+ //文件的
+ "/sysFileInfo/upload",
+ "/sysFileInfo/download",
+ "/sysFileInfo/preview",
+
+ //druid的
+ "/druid/**",
+
+ };
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/SymbolConstant.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/SymbolConstant.java
new file mode 100644
index 00000000..fe9401ab
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/consts/SymbolConstant.java
@@ -0,0 +1,90 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.consts;
+
+/**
+ * 符号常量
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 12:05
+ */
+public interface SymbolConstant {
+
+ String PERIOD = ".";
+
+ String COMMA = ",";
+
+ String COLON = ":";
+
+ String SEMICOLON = ";";
+
+ String EXCLAMATION_MARK = "!";
+
+ String QUESTION_MARK = "?";
+
+ String HYPHEN = "-";
+
+ String ASTERISK = "*";
+
+ String APOSTROPHE = "`";
+
+ String DASH = "-";
+
+ String UNDER_SCORE = "_";
+
+ String SINGLE_QUOTATION_MARK = "'";
+
+ String DOUBLE_QUOTATION_MARK = "\"";
+
+ String LEFT_ROUND_BRACKETS = "(";
+
+ String RIGHT_ROUND_BRACKETS = ")";
+
+ String LEFT_SQUARE_BRACKETS = "[";
+
+ String RIGHT_SQUARE_BRACKETS = "]";
+
+ String LEFT_ANGLE_BRACKETS = "<";
+
+ String RIGHT_ANGLE_BRACKETS = ">";
+
+ String LEFT_CURLY_BRACKETS = "{";
+
+ String RIGHT_CURLY_BRACKETS = "}";
+
+ String DOLLAR = "$";
+
+ String PERCENT = "%";
+
+ String LEFT_DIVIDE = "/";
+
+ String RIGHT_DIVIDE = "\\";
+
+ String LEFT_DOUBLE_DIVIDE = "//";
+
+ String RIGHT_DOUBLE_DIVIDE = "\\\\";
+
+ String EQUAL = "=";
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/constant/ConstantContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/constant/ConstantContext.java
new file mode 100644
index 00000000..104c4ade
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/constant/ConstantContext.java
@@ -0,0 +1,78 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.constant;
+
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+
+/**
+ * 系统参数配置容器
+ *
+ * @author yubaoshan
+ * @date 2019/6/20 13:37
+ */
+public class ConstantContext {
+
+ /**
+ * 所有的常量,可以增删改查
+ */
+ private static final Dict CONSTANTS_HOLDER = Dict.create();
+
+ /**
+ * 添加系统常量
+ *
+ * @author yubaoshan
+ * @date 2020/6/20 22:32
+ */
+ public static void putConstant(String code, Object value) {
+ if (ObjectUtil.hasEmpty(code, value)) {
+ return;
+ }
+ CONSTANTS_HOLDER.put(code, value);
+ }
+
+ /**
+ * 删除常量,系统常量无法删除,在sysConfig已判断
+ *
+ * @author yubaoshan
+ * @date 2020/6/20 22:32
+ */
+ public static void deleteConstant(String code) {
+ if (ObjectUtil.hasEmpty(code)) {
+ return;
+ }
+ CONSTANTS_HOLDER.remove(code);
+ }
+
+ /**
+ * 获取系统常量本身
+ *
+ * @author yubaoshan
+ * @date 2020/6/20 22:32
+ */
+ public static Dict me() {
+ return CONSTANTS_HOLDER;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/constant/ConstantContextHolder.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/constant/ConstantContextHolder.java
new file mode 100644
index 00000000..3ce36e66
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/constant/ConstantContextHolder.java
@@ -0,0 +1,393 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.constant;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.pojo.email.EmailConfigs;
+import com.cn.xiaonuo.core.pojo.oauth.OauthConfigs;
+import com.cn.xiaonuo.core.pojo.sms.AliyunSmsConfigs;
+import com.cn.xiaonuo.core.pojo.sms.TencentSmsConfigs;
+
+import java.util.List;
+
+import static com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum.CONSTANT_EMPTY;
+
+/**
+ * 系统参数配置获取
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 15:34
+ */
+public class ConstantContextHolder {
+
+ private static final Log log = Log.get();
+
+ /**
+ * 获取租户功能是否开启
+ *
+ * @author xuyuxiang
+ * @date 2020/9/3
+ */
+ public static Boolean getTenantOpenFlag() {
+ return getSysConfigWithDefault("XIAONUO_TENANT_OPEN", Boolean.class, false);
+ }
+
+ /**
+ * 获取druid监控的密码
+ *
+ * @author yubaoshan
+ * @date 2020/7/8 9:53
+ */
+ public static String getDruidMonitorPassword() {
+ return getSysConfigWithDefault("XIAONUO_DRUID_PASSWORD", String.class, RandomUtil.randomString(10));
+ }
+
+ /**
+ * 获取druid的账号
+ *
+ * @author yubaoshan
+ * @date 2020/7/8 9:53
+ */
+ public static String getDruidMonitorUsername() {
+ return getSysConfigWithDefault("XIAONUO_DRUID_USERNAME", String.class, RandomUtil.randomString(10));
+ }
+
+ /**
+ * 获取放开xss过滤的接口
+ *
+ * @author yubaoshan
+ * @date 2020/6/20 22:13
+ */
+ public static List getUnXssFilterUrl() {
+ String xiaoNuoUnXssFilterUrl = getSysConfigWithDefault("XIAONUO_UN_XSS_FILTER_URL", String.class, null);
+ if (ObjectUtil.isEmpty(xiaoNuoUnXssFilterUrl)) {
+ return CollectionUtil.newArrayList();
+ } else {
+ return CollectionUtil.toList(xiaoNuoUnXssFilterUrl.split(SymbolConstant.COMMA));
+ }
+ }
+
+ /**
+ * 获取演示环境开关是否开启,默认为false
+ *
+ * @author yubaoshan
+ * @date 2020/6/20 22:13
+ */
+ public static Boolean getDemoEnvFlag() {
+ return getSysConfigWithDefault("XIAONUO_DEMO_ENV_FLAG", Boolean.class, false);
+ }
+
+ /**
+ * 邮件的配置
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 18:08
+ */
+ public static EmailConfigs getEmailConfigs() {
+ String host = getSysConfig("XIAONUO_EMAIL_HOST", String.class, true);
+ String username = getSysConfig("XIAONUO_EMAIL_USERNAME", String.class, true);
+ String password = getSysConfig("XIAONUO_EMAIL_PASSWORD", String.class, true);
+ Integer port = getSysConfig("XIAONUO_EMAIL_PORT", Integer.class, true);
+ String from = getSysConfig("XIAONUO_EMAIL_FROM", String.class, true);
+ Boolean ssl = getSysConfig("XIAONUO_EMAIL_SSL", Boolean.class, true);
+
+ EmailConfigs emailConfigs = new EmailConfigs();
+ emailConfigs.setHost(host);
+ emailConfigs.setUser(username);
+ emailConfigs.setPass(password);
+ emailConfigs.setPort(port);
+ emailConfigs.setFrom(from);
+ emailConfigs.setSslEnable(ssl);
+ return emailConfigs;
+ }
+
+ /**
+ * 获取腾讯云短信的配置
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 18:08
+ */
+ public static TencentSmsConfigs getTencentSmsConfigs() {
+ String xiaoNuoTencentSmsSecretId = getSysConfig("XIAONUO_TENCENT_SMS_SECRET_ID", String.class, true);
+ String xiaoNuoTencentSmsSecretKey = getSysConfig("XIAONUO_TENCENT_SMS_SECRET_KEY", String.class, true);
+ String xiaoNuoTencentSmsSdkAppId = getSysConfig("XIAONUO_TENCENT_SMS_SDK_APP_ID", String.class, true);
+ String xiaoNuoTencentSmsSign = getSysConfig("XIAONUO_TENCENT_SMS_SIGN", String.class, true);
+
+ TencentSmsConfigs tencentSmsConfigs = new TencentSmsConfigs();
+ tencentSmsConfigs.setSecretId(xiaoNuoTencentSmsSecretId);
+ tencentSmsConfigs.setSecretKey(xiaoNuoTencentSmsSecretKey);
+ tencentSmsConfigs.setSdkAppId(xiaoNuoTencentSmsSdkAppId);
+ tencentSmsConfigs.setSign(xiaoNuoTencentSmsSign);
+ return tencentSmsConfigs;
+ }
+
+ /**
+ * 获取阿里云短信的配置
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 18:08
+ */
+ public static AliyunSmsConfigs getAliyunSmsConfigs() {
+ String xiaoNuoSmsAccesskeyId = getSysConfig("XIAONUO_ALIYUN_SMS_ACCESSKEY_ID", String.class, true);
+ String xiaoNuoSmsAccesskeySecret = getSysConfig("XIAONUO_ALIYUN_SMS_ACCESSKEY_SECRET", String.class, true);
+ String xiaoNuoSmsSignName = getSysConfig("XIAONUO_ALIYUN_SMS_SIGN_NAME", String.class, true);
+ String xiaoNuoSmsLoginTemplateCode = getSysConfig("XIAONUO_ALIYUN_SMS_LOGIN_TEMPLATE_CODE", String.class, true);
+ String xiaoNuoSmsInvalidateMinutes = getSysConfig("XIAONUO_ALIYUN_SMS_INVALIDATE_MINUTES", String.class, true);
+
+ AliyunSmsConfigs aliyunSmsProperties = new AliyunSmsConfigs();
+ aliyunSmsProperties.setAccessKeyId(xiaoNuoSmsAccesskeyId);
+ aliyunSmsProperties.setAccessKeySecret(xiaoNuoSmsAccesskeySecret);
+ aliyunSmsProperties.setSignName(xiaoNuoSmsSignName);
+ aliyunSmsProperties.setLoginTemplateCode(xiaoNuoSmsLoginTemplateCode);
+ aliyunSmsProperties.setInvalidateMinutes(Convert.toInt(xiaoNuoSmsInvalidateMinutes));
+ return aliyunSmsProperties;
+ }
+
+ /**
+ * 获取jwt密钥,默认是32位随机字符串
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 18:08
+ */
+ public static String getJwtSecret() {
+ return getSysConfigWithDefault("XIAONUO_JWT_SECRET", String.class, RandomUtil.randomString(32));
+ }
+
+ /**
+ * 获取默认密码
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 18:08
+ */
+ public static String getDefaultPassWord() {
+ return getSysConfigWithDefault("XIAONUO_DEFAULT_PASSWORD", String.class, CommonConstant.DEFAULT_PASSWORD);
+ }
+
+ /**
+ * 获取会话过期时间,默认2小时
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 16:18
+ */
+ public static Long getSessionTokenExpireSec() {
+ return getSysConfigWithDefault("XIAONUO_SESSION_EXPIRE", Long.class, 2 * 60 * 60L);
+ }
+
+ /**
+ * 获取token过期时间(单位:秒)
+ *
+ * 默认时间1天
+ *
+ * @author xuyuxiang
+ * @date 2020/6/19 18:08
+ */
+ public static Long getTokenExpireSec() {
+ return getSysConfigWithDefault("XIAONUO_TOKEN_EXPIRE", Long.class, 86400L);
+ }
+
+ /**
+ * 获取自定义的windows环境本地文件上传路径
+ *
+ * @author xuyuxiang
+ * @date 2020/6/19 18:09
+ */
+ public static String getDefaultFileUploadPathForWindows() {
+ return getSysConfigWithDefault("XIAONUO_FILE_UPLOAD_PATH_FOR_WINDOWS", String.class, "");
+ }
+
+ /**
+ * 获取自定义的linux环境本地文件上传路径
+ *
+ * @author xuyuxiang
+ * @date 2020/6/19 18:09
+ */
+ public static String getDefaultFileUploadPathForLinux() {
+ return getSysConfigWithDefault("XIAONUO_FILE_UPLOAD_PATH_FOR_LINUX", String.class, "");
+ }
+
+ /**
+ * 获取是否允许单用户登陆的开关, 默认为false
+ *
+ * @author xuyuxiang
+ * @date 2020/6/19 18:09
+ */
+ public static Boolean getEnableSingleLogin() {
+ return getSysConfigWithDefault("XIAONUO_ENABLE_SINGLE_LOGIN", Boolean.class, false);
+ }
+
+ /**
+ * 获取阿里云定位接口
+ *
+ * @author xuyuxiang
+ * @date 2020/7/20 9:20
+ **/
+ public static String getIpGeoApi() {
+ return getSysConfig("XIAONUO_IP_GEO_API", String.class, false);
+ }
+
+ /**
+ * 获取阿里云定位appCode
+ *
+ * @author xuyuxiang
+ * @date 2020/7/20 10:33
+ **/
+ public static String getIpGeoAppCode() {
+ return getSysConfig("XIAONUO_IP_GEO_APP_CODE", String.class, false);
+ }
+
+ /**
+ * 获取Oauth码云第三方登录的配置
+ *
+ * @author xuyuxiang
+ * @date 2020/7/28 17:16
+ **/
+ public static OauthConfigs getGiteeOauthConfigs() {
+ String xiaoNuoClientId = getSysConfig("XIAONUO_OAUTH_GITEE_CLIENT_ID", String.class, true);
+ String xiaoNuoClientSecret = getSysConfig("XIAONUO_OAUTH_GITEE_CLIENT_SECRET", String.class, true);
+ String xiaoNuoRedirectUri = getSysConfig("XIAONUO_OAUTH_GITEE_REDIRECT_URI", String.class, true);
+
+ OauthConfigs oauthConfigs = new OauthConfigs();
+ oauthConfigs.setClientId(xiaoNuoClientId);
+ oauthConfigs.setClientSecret(xiaoNuoClientSecret);
+ oauthConfigs.setRedirectUri(xiaoNuoRedirectUri);
+ return oauthConfigs;
+ }
+
+ /**
+ * 获取OauthGithub第三方登录的配置
+ *
+ * @author xuyuxiang
+ * @date 2020/7/28 17:16
+ **/
+ public static OauthConfigs getGithubOauthConfigs() {
+ String xiaoNuoClientId = getSysConfig("XIAONUO_OAUTH_GITHUB_CLIENT_ID", String.class, true);
+ String xiaoNuoClientSecret = getSysConfig("XIAONUO_OAUTH_GITHUB_CLIENT_SECRET", String.class, true);
+ String xiaoNuoRedirectUri = getSysConfig("XIAONUO_OAUTH_GITHUB_REDIRECT_URI", String.class, true);
+
+ OauthConfigs oauthConfigs = new OauthConfigs();
+ oauthConfigs.setClientId(xiaoNuoClientId);
+ oauthConfigs.setClientSecret(xiaoNuoClientSecret);
+ oauthConfigs.setRedirectUri(xiaoNuoRedirectUri);
+ return oauthConfigs;
+ }
+
+ /**
+ * 获取是否允许Oauth用户登陆的开关, 默认为false
+ *
+ * @author xuyuxiang
+ * @date 2020/7/28 16:37
+ **/
+ public static Boolean getEnableOauthLogin() {
+ return getSysConfigWithDefault("XIAONUO_ENABLE_OAUTH_LOGIN", Boolean.class, false);
+ }
+
+ /**
+ * 获取前端项目的地址
+ *
+ * @author xuyuxiang
+ * @date 2020/7/29 14:08
+ **/
+ public static String getWebUrl() {
+ return getSysConfig("XIAONUO_WEB_URL", String.class, true);
+ }
+
+ /**
+ * 获取支付宝支付成功转发地址
+ *
+ * @author xuyuxiang
+ * @date 2020/7/29 14:08
+ **/
+ public static String getAlipayReturnUrl() {
+ return getSysConfig("XIAONUO_ALIPAY_RETURN_URL", String.class, true);
+ }
+
+ /**
+ * 获取config表中的配置,如果为空返回默认值
+ *
+ * @param configCode 变量名称,对应sys_config表中的code
+ * @param clazz 返回变量值的类型
+ * @param defaultValue 如果结果为空返回此默认值
+ * @author yubaoshan
+ * @date 2020/6/20 22:03
+ */
+ public static T getSysConfigWithDefault(String configCode, Class clazz, T defaultValue) {
+ String configValue = ConstantContext.me().getStr(configCode);
+ if (ObjectUtil.isEmpty(configValue)) {
+ // 将默认值加入到缓存常量
+ log.warn(">>> 系统配置sys_config表中存在空项,configCode为:{},系统采用默认值:{}", configCode, defaultValue);
+ ConstantContext.me().put(configCode, defaultValue);
+ return defaultValue;
+ } else {
+ try {
+ return Convert.convert(clazz, configValue);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+ }
+
+ /**
+ * 获取config表中的配置,如果为空,是否抛出异常
+ *
+ * @param configCode 变量名称,对应sys_config表中的code
+ * @param clazz 返回变量值的类型
+ * @param nullThrowExp 若为空是否抛出异常
+ * @author yubaoshan
+ * @date 2020/6/20 22:03
+ */
+ public static T getSysConfig(String configCode, Class clazz, Boolean nullThrowExp) {
+ String configValue = ConstantContext.me().getStr(configCode);
+ if (ObjectUtil.isEmpty(configValue)) {
+ if (nullThrowExp) {
+ String format = StrUtil.format(">>> 系统配置sys_config表中存在空项,configCode为:{}", configCode);
+ log.error(format);
+ throw new ServiceException(CONSTANT_EMPTY.getCode(), format);
+ } else {
+ return null;
+ }
+ } else {
+ try {
+ return Convert.convert(clazz, configValue);
+ } catch (Exception e) {
+ if (nullThrowExp) {
+ String format = StrUtil.format(">>> 系统配置sys_config表中存在格式错误的值,configCode={},configValue={}", configCode, configValue);
+ log.error(format);
+ throw new ServiceException(CONSTANT_EMPTY.getCode(), format);
+ } else {
+ return null;
+ }
+ }
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/group/RequestGroupContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/group/RequestGroupContext.java
new file mode 100644
index 00000000..224b27df
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/group/RequestGroupContext.java
@@ -0,0 +1,67 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.group;
+
+/**
+ * 保存控制器的方法上的校验group class
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+public class RequestGroupContext {
+
+ private static final ThreadLocal> GROUP_CLASS_HOLDER = new ThreadLocal<>();
+
+ /**
+ * 设置临时的group class
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void set(Class> groupValue) {
+ GROUP_CLASS_HOLDER.set(groupValue);
+ }
+
+ /**
+ * 获取临时缓存的group class
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static Class> get() {
+ return GROUP_CLASS_HOLDER.get();
+ }
+
+ /**
+ * 清除临时缓存的group class
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void clear() {
+ GROUP_CLASS_HOLDER.remove();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/group/RequestParamIdContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/group/RequestParamIdContext.java
new file mode 100644
index 00000000..113d8e4f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/group/RequestParamIdContext.java
@@ -0,0 +1,69 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.group;
+
+/**
+ * 临时保存参数id字段值,用于唯一性校验
+ *
+ * 注意:如果要用@TableUniqueValue这个校验,必须得主键的字段名是id,否则会校验失败
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+public class RequestParamIdContext {
+
+ private static final ThreadLocal PARAM_ID_HOLDER = new ThreadLocal<>();
+
+ /**
+ * 设置id
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void set(Long id) {
+ PARAM_ID_HOLDER.set(id);
+ }
+
+ /**
+ * 获取id
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static Long get() {
+ return PARAM_ID_HOLDER.get();
+ }
+
+ /**
+ * 清除缓存id
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void clear() {
+ PARAM_ID_HOLDER.remove();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/login/LoginContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/login/LoginContext.java
new file mode 100644
index 00000000..73274510
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/login/LoginContext.java
@@ -0,0 +1,169 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.login;
+
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+
+import java.util.List;
+
+/**
+ * 登录用户上下文
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 12:16
+ */
+public interface LoginContext {
+
+ /**
+ * 获取当前登录用户
+ *
+ * @return 当前登录用户信息
+ * @author xuyuxiang
+ * @date 2020/3/13 14:40
+ */
+ SysLoginUser getSysLoginUser();
+
+ /**
+ * 获取当前登录用户,如未登录,则返回null,不抛异常
+ *
+ * @return 当前登录用户信息
+ * @author xuyuxiang
+ * @date 2020/3/13 14:40
+ */
+ SysLoginUser getSysLoginUserWithoutException();
+
+ /**
+ * 获取当前登录用户的id
+ *
+ * @return 当前登录用户的id
+ * @author xuyuxiang
+ * @date 2020/3/18 19:25
+ */
+ Long getSysLoginUserId();
+
+ /**
+ * 判断用户是否登录
+ *
+ * @return 是否登录,true是,false否
+ * @author xuyuxiang
+ * @date 2020/3/18 19:22
+ */
+ boolean hasLogin();
+
+ /**
+ * 获取当前登录用户的账户
+ *
+ * @return 当前登陆用户的账户account
+ * @author xuyuxiang
+ * @date 2020/3/19 20:37
+ */
+ String getSysLoginUserAccount();
+
+ /**
+ * 判断当前登录用户是否有某资源的访问权限
+ *
+ * @param requestUri 请求的url
+ * @return 是否有访问权限,true是,false否
+ * @author xuyuxiang
+ * @date 2020/3/23 8:48
+ */
+ boolean hasPermission(String requestUri);
+
+ /**
+ * 判断当前登录用户是否包含某个角色
+ *
+ * @param roleCode 角色编码
+ * @return 是否包含该角色,true是,false否
+ * @author xuyuxiang
+ * @date 2020/3/23 8:53
+ */
+ boolean hasRole(String roleCode);
+
+ /**
+ * 判断当前登录用户是否包含任意一个角色
+ *
+ * @param roleCodes 角色集合,逗号拼接
+ * @return 是否包含任一角色,true是,false否
+ * @author xuyuxiang
+ * @date 2020/3/23 8:54
+ */
+ boolean hasAnyRole(String roleCodes);
+
+ /**
+ * 判断当前登录用户是否是超级管理员
+ *
+ * @return 当前登录用户是否是超级管理员
+ * @author xuyuxiang
+ * @date 2020/3/23 17:50
+ */
+ boolean isSuperAdmin();
+
+ /**
+ * 判断当前登录用户是否包含所有角色
+ *
+ * @param roleCodes 角色集合,逗号拼接
+ * @return 是否包含所有角色,true是,false否
+ * @author xuyuxiang
+ * @date 2020/4/5 10:28
+ */
+ boolean hasAllRole(String roleCodes);
+
+ /**
+ * 获取当前登录用户的数据范围集合(组织机构id集合)
+ *
+ * @return 数据范围集合(组织机构id集合)
+ * @author xuyuxiang
+ * @date 2020/4/5 17:20
+ */
+ List getLoginUserDataScopeIdList();
+
+ /**
+ * 获取当前登录用户的组织机构id
+ *
+ * @return 当前登录用户的组织机构id
+ * @author xuyuxiang
+ * @date 2020/4/5 18:31
+ */
+ Long getSysLoginUserOrgId();
+
+ /**
+ * 获取当前登录用户的角色id集合
+ *
+ * @return 当前登录用户角色id集合
+ * @author xuyuxiang
+ * @date 2020/4/20 16:04
+ */
+ List getLoginUserRoleIds();
+
+ /**
+ * 获取最新的用户信息,用于修改之后前端获取
+ *
+ * @return 最新的用户信息
+ * @author xuyuxiang
+ * @date 2020/9/20 15:18
+ **/
+ SysLoginUser getSysLoginUserUpToDate();
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/login/LoginContextHolder.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/login/LoginContextHolder.java
new file mode 100644
index 00000000..e8574b20
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/login/LoginContextHolder.java
@@ -0,0 +1,41 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.login;
+
+import cn.hutool.extra.spring.SpringUtil;
+
+/**
+ * 当前登录用户信息获取的接口
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 12:21
+ */
+public class LoginContextHolder {
+
+ public static LoginContext me() {
+ return SpringUtil.getBean(LoginContext.class);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/param/RequestParamContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/param/RequestParamContext.java
new file mode 100644
index 00000000..e3bb6e65
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/param/RequestParamContext.java
@@ -0,0 +1,89 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.param;
+
+import cn.hutool.core.lang.Dict;
+
+/**
+ * 临时保存http请求的参数
+ *
+ * 可以保存@RequestBody的可以保存parameter方式传参的
+ *
+ * @author xuyuxiang
+ * @date 2020/8/20
+ */
+public class RequestParamContext {
+
+ private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
+
+ /**
+ * 保存请求参数
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void set(Dict requestParam) {
+ CONTEXT_HOLDER.set(requestParam);
+ }
+
+ /**
+ * 保存请求参数
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void setObject(Object requestParam) {
+
+ if (requestParam == null) {
+ return;
+ }
+
+ if (requestParam instanceof Dict) {
+ CONTEXT_HOLDER.set((Dict) requestParam);
+ } else {
+ CONTEXT_HOLDER.set(Dict.parse(requestParam));
+ }
+ }
+
+ /**
+ * 获取请求参数
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static Dict get() {
+ return CONTEXT_HOLDER.get();
+ }
+
+ /**
+ * 清除请求参数
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void clear() {
+ CONTEXT_HOLDER.remove();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/requestno/RequestNoContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/requestno/RequestNoContext.java
new file mode 100644
index 00000000..5511c91a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/requestno/RequestNoContext.java
@@ -0,0 +1,66 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.requestno;
+
+/**
+ * 临时保存当前请求号
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+public class RequestNoContext {
+
+ private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
+
+ /**
+ * 保存请求号
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void set(String requestNo) {
+ CONTEXT_HOLDER.set(requestNo);
+ }
+
+ /**
+ * 获取请求号
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static String get() {
+ return CONTEXT_HOLDER.get();
+ }
+
+ /**
+ * 清除请求号
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 20:17
+ */
+ public static void clear() {
+ CONTEXT_HOLDER.remove();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/resources/ApiResourceContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/resources/ApiResourceContext.java
new file mode 100644
index 00000000..1a20125b
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/resources/ApiResourceContext.java
@@ -0,0 +1,93 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.resources;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import java.util.Set;
+
+/**
+ * 存放本系统所有@RequestMapping的Url
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:32
+ */
+public class ApiResourceContext {
+
+ /**
+ * 所有资源的url
+ */
+ private static final Set API_URLS = CollectionUtil.newHashSet();
+
+ /**
+ * 添加一批url
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:35
+ */
+ public static void addBatchUrls(Set urls) {
+ if (ObjectUtil.isEmpty(urls)) {
+ return;
+ }
+ API_URLS.addAll(urls);
+ }
+
+ /**
+ * 添加url
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:35
+ */
+ public static void addUrl(String url) {
+ if (ObjectUtil.isEmpty(url)) {
+ return;
+ }
+ API_URLS.add(url);
+ }
+
+ /**
+ * 删除url
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:35
+ */
+ public static void deleteUrl(String url) {
+ if (ObjectUtil.isEmpty(url)) {
+ return;
+ }
+ API_URLS.remove(url);
+ }
+
+ /**
+ * 获取系统的所有url
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:36
+ */
+ public static Set getApiUrls() {
+ return API_URLS;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/system/SystemContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/system/SystemContext.java
new file mode 100644
index 00000000..31a6ad9d
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/system/SystemContext.java
@@ -0,0 +1,144 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.system;
+
+import cn.hutool.core.lang.Dict;
+import com.cn.xiaonuo.core.pojo.base.validate.UniqueValidateParam;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.core.pojo.base.validate.UniqueValidateParam;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+
+import java.util.List;
+
+/**
+ * 系统相关上下文接口,在system模块实现,用于某些模块不能引用system模块时,通过此方式调用system相关功能
+ *
+ * @author xuyuxiang
+ * @date 2020/5/6 14:52
+ */
+public interface SystemContext {
+
+ /**
+ * 根据用户id获取姓名
+ *
+ * @param userId 用户id
+ * @return 用户姓名
+ * @author xuyuxiang
+ * @date 2020/5/6 14:57
+ */
+ String getNameByUserId(Long userId);
+
+ /**
+ * 根据角色id获取角色名称
+ *
+ * @param roleId 角色id
+ * @return 角色名称
+ * @author xuyuxiang
+ * @date 2020/5/22 15:55
+ */
+ String getNameByRoleId(Long roleId);
+
+ /**
+ * 根据token获取登录用户信息
+ *
+ * @param token token
+ * @return 登录用户信息
+ * @author xuyuxiang
+ * @date 2020/3/13 11:59
+ */
+ SysLoginUser getLoginUserByToken(String token);
+
+ /**
+ * 根据用户账号模糊搜索系统用户列表
+ *
+ * @param account 账号
+ * @return 增强版hashMap,格式:[{"id:":123, "firstName":"张三"}]
+ * @author xuyuxiang
+ * @date 2020/6/1 15:12
+ */
+ List listUser(String account);
+
+ /**
+ * 根据角色名模糊搜索系统角色列表
+ *
+ * @param name 角色名
+ * @return 增强版hashMap,格式:[{"id:":123, "name":"总经理"}]
+ * @author xuyuxiang
+ * @date 2020/6/1 15:13
+ */
+ List listRole(String name);
+
+ /**
+ * 根据id判断是否是用户
+ *
+ * @param userOrRoleId 用户或角色id
+ * @return true是 false否
+ * @author xuyuxiang
+ * @date 2020/8/4 20:56
+ */
+ boolean isUser(Long userOrRoleId);
+
+ /**
+ * 根据id判断是否是角色
+ *
+ * @param userOrRoleId 用户或角色id
+ * @return true是 false否
+ * @author xuyuxiang
+ * @date 2020/8/4 20:56
+ */
+ boolean isRole(Long userOrRoleId);
+
+ /**
+ * 根据字典类型获取字典的code值
+ *
+ * @param dictTypeCodes 字典类型编码值
+ * @return 字典的code值
+ * @author xuyuxiang
+ * @date 2020/8/9 14:18
+ */
+ List getDictCodesByDictTypeCode(String... dictTypeCodes);
+
+ /**
+ * 校验某个表中,某一列是否存在重复的值
+ *
+ * 一般用于唯一code校验
+ *
+ * @param uniqueValidateParam 被校验的参数
+ * @return true-是唯一的值,false-不是唯一的
+ * @author xuyuxiang
+ * @date 2020/8/9 21:41
+ */
+ boolean tableUniValueFlag(UniqueValidateParam uniqueValidateParam);
+
+ /**
+ * 获取系统用户id集合
+ *
+ * @return 用户id集合
+ * @author xuyuxiang
+ * @date 2020/9/11 17:53
+ **/
+ List getAllUserIdList();
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/system/SystemContextHolder.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/system/SystemContextHolder.java
new file mode 100644
index 00000000..631e41cb
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/context/system/SystemContextHolder.java
@@ -0,0 +1,41 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.context.system;
+
+import cn.hutool.extra.spring.SpringUtil;
+
+/**
+ * 使用system模块相关功能的接口
+ *
+ * @author xuyuxiang
+ * @date 2020/5/6 14:56
+ */
+public class SystemContextHolder {
+
+ public static SystemContext me() {
+ return SpringUtil.getBean(SystemContext.class);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/dbs/CurrentDataSourceContext.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/dbs/CurrentDataSourceContext.java
new file mode 100644
index 00000000..a5987fea
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/dbs/CurrentDataSourceContext.java
@@ -0,0 +1,43 @@
+package com.cn.xiaonuo.core.dbs;
+
+/**
+ * datasource的上下文
+ *
+ * @author xuyuxiang
+ * @date 2020/8/24
+ */
+public class CurrentDataSourceContext {
+
+ private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
+
+ /**
+ * 设置数据源类型
+ *
+ * @param dataSourceType 数据库类型
+ * @date 2020/8/24
+ */
+ public static void setDataSourceType(String dataSourceType) {
+ CONTEXT_HOLDER.set(dataSourceType);
+ }
+
+ /**
+ * 获取数据源类型
+ *
+ * @author xuyuxiang
+ * @date 2020/8/24
+ */
+ public static String getDataSourceType() {
+ return CONTEXT_HOLDER.get();
+ }
+
+ /**
+ * 清除数据源类型
+ *
+ * @author xuyuxiang
+ * @date 2020/8/24
+ */
+ public static void clearDataSourceType() {
+ CONTEXT_HOLDER.remove();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/MailSender.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/MailSender.java
new file mode 100644
index 00000000..5c737451
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/MailSender.java
@@ -0,0 +1,30 @@
+package com.cn.xiaonuo.core.email;
+
+
+import com.cn.xiaonuo.core.email.modular.model.SendMailParam;
+
+/**
+ * 邮件收发统一接口
+ *
+ * @author xuyuxiang
+ * @date 2018-07-08-下午3:26
+ */
+public interface MailSender {
+
+ /**
+ * 发送普通邮件
+ *
+ * @author xuyuxiang
+ * @date 2018/7/8 下午3:34
+ */
+ void sendMail(SendMailParam sendMailParam);
+
+ /**
+ * 发送html的邮件
+ *
+ * @author xuyuxiang
+ * @date 2020/6/9 22:58
+ */
+ void sendMailHtml(SendMailParam sendMailParam);
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/SimpleMailSender.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/SimpleMailSender.java
new file mode 100644
index 00000000..e320f8f9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/SimpleMailSender.java
@@ -0,0 +1,72 @@
+package com.cn.xiaonuo.core.email.modular;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.mail.MailAccount;
+import cn.hutool.extra.mail.MailUtil;
+import com.cn.xiaonuo.core.email.MailSender;
+import com.cn.xiaonuo.core.email.modular.exception.MailSendException;
+import com.cn.xiaonuo.core.email.modular.model.SendMailParam;
+
+/**
+ * 邮件发送器
+ *
+ * @author xuyuxiang
+ * @date 2020/6/9 22:54
+ */
+public class SimpleMailSender implements MailSender {
+
+ /**
+ * 邮件配置
+ */
+ private final MailAccount mailAccount;
+
+ public SimpleMailSender(MailAccount mailAccount) {
+ this.mailAccount = mailAccount;
+ }
+
+ @Override
+ public void sendMail(SendMailParam sendMailParam) {
+
+ //校验发送邮件的参数
+ assertSendMailParams(sendMailParam);
+
+ //spring发送邮件
+ MailUtil.send(mailAccount, CollUtil.newArrayList(sendMailParam.getTo()), sendMailParam.getTitle(), sendMailParam.getContent(), false);
+ }
+
+ @Override
+ public void sendMailHtml(SendMailParam sendMailParam) {
+
+ //校验发送邮件的参数
+ assertSendMailParams(sendMailParam);
+
+ //spring发送邮件
+ MailUtil.send(mailAccount, CollUtil.newArrayList(sendMailParam.getTo()), sendMailParam.getTitle(), sendMailParam.getContent(), true);
+ }
+
+ /**
+ * 校验发送邮件的请求参数
+ *
+ * @author xuyuxiang
+ * @date 2018/7/8 下午6:41
+ */
+ private void assertSendMailParams(SendMailParam sendMailParam) {
+ if (sendMailParam == null) {
+ throw new MailSendException(400, "请求参数为空");
+ }
+
+ if (ObjectUtil.isEmpty(sendMailParam.getTo())) {
+ throw new MailSendException(400, "收件人邮箱为空");
+ }
+
+ if (ObjectUtil.isEmpty(sendMailParam.getTitle())) {
+ throw new MailSendException(400, "邮件标题为空");
+ }
+
+ if (ObjectUtil.isEmpty(sendMailParam.getContent())) {
+ throw new MailSendException(400, "邮件内容为空");
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/exception/MailSendException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/exception/MailSendException.java
new file mode 100644
index 00000000..7ce2d1e7
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/exception/MailSendException.java
@@ -0,0 +1,24 @@
+package com.cn.xiaonuo.core.email.modular.exception;
+
+import lombok.Getter;
+
+/**
+ * 邮件发送异常
+ *
+ * @author xuyuxiang
+ * @date 2018-07-06-下午3:00
+ */
+@Getter
+public class MailSendException extends RuntimeException {
+
+ private final Integer code;
+
+ private final String errorMessage;
+
+ public MailSendException(Integer code, String errorMessage) {
+ super(errorMessage);
+ this.code = code;
+ this.errorMessage = errorMessage;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/model/SendMailParam.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/model/SendMailParam.java
new file mode 100644
index 00000000..061b2c82
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/email/modular/model/SendMailParam.java
@@ -0,0 +1,28 @@
+package com.cn.xiaonuo.core.email.modular.model;
+
+import lombok.Data;
+
+/**
+ * 发送邮件的请求参数
+ *
+ * @author xuyuxiang
+ * @date 2018-07-05 21:19
+ */
+@Data
+public class SendMailParam {
+
+ /**
+ * 发送给某人的邮箱
+ */
+ private String to;
+
+ /**
+ * 邮件标题
+ */
+ private String title;
+
+ /**
+ * 邮件内容
+ */
+ private String content;
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/CommonStatusEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/CommonStatusEnum.java
new file mode 100644
index 00000000..829e7d23
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/CommonStatusEnum.java
@@ -0,0 +1,80 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.enums;
+
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.StatusExceptionEnum;
+import lombok.Getter;
+
+/**
+ * 公共状态
+ *
+ * @author yubaoshan
+ * @date 2017/1/22 12:14
+ */
+@Getter
+public enum CommonStatusEnum {
+
+ /**
+ * 正常
+ */
+ ENABLE(0, "正常"),
+
+ /**
+ * 停用
+ */
+ DISABLE(1, "停用"),
+
+ /**
+ * 删除
+ */
+ DELETED(2, "删除");
+
+ private final Integer code;
+
+ private final String message;
+
+ CommonStatusEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ /**
+ * 检查请求参数的状态是否正确
+ *
+ * @author yubaoshan
+ * @date 2020/4/30 22:43
+ */
+ public static void validateStatus(Integer code) {
+ if (code == null) {
+ throw new ServiceException(StatusExceptionEnum.REQUEST_EMPTY);
+ }
+ if (ENABLE.getCode().equals(code) || DISABLE.getCode().equals(code)) {
+ return;
+ }
+ throw new ServiceException(StatusExceptionEnum.NOT_WRITE_STATUS);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/DbIdEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/DbIdEnum.java
new file mode 100644
index 00000000..5f862d46
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/DbIdEnum.java
@@ -0,0 +1,69 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 不同数据库类型的枚举
+ *
+ * 用于标识mapping.xml中不同数据库的标识
+ *
+ * @author yubaoshan
+ * @date 2020/6/20 21:08
+ */
+@Getter
+public enum DbIdEnum {
+
+ /**
+ * mysql
+ */
+ MYSQL("mysql", "mysql"),
+
+ /**
+ * pgsql
+ */
+ PG_SQL("pgsql", "postgresql"),
+
+ /**
+ * oracle
+ */
+ ORACLE("oracle", "oracle"),
+
+ /**
+ * mssql
+ */
+ MS_SQL("mssql", "sqlserver");
+
+ private final String code;
+
+ private final String name;
+
+ DbIdEnum(String code, String name) {
+ this.code = code;
+ this.name = name;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/DocumentFormatEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/DocumentFormatEnum.java
new file mode 100644
index 00000000..b51a0d6c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/DocumentFormatEnum.java
@@ -0,0 +1,106 @@
+package com.cn.xiaonuo.core.enums;
+
+import org.jodconverter.document.DefaultDocumentFormatRegistry;
+import org.jodconverter.document.DocumentFormat;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 文档类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/7/6 15:00
+ */
+public enum DocumentFormatEnum {
+
+ /**
+ * 文档doc格式
+ */
+ DOC {
+ @Override
+ public DocumentFormat getFormFormat() {
+ return DefaultDocumentFormatRegistry.DOC;
+ }
+ },
+
+ /**
+ * 文档docx格式
+ */
+ DOCX {
+ @Override
+ public DocumentFormat getFormFormat() {
+ return DefaultDocumentFormatRegistry.DOCX;
+ }
+ },
+
+ /**
+ * 演示文稿ppt格式
+ */
+ PPT {
+ @Override
+ public DocumentFormat getFormFormat() {
+ return DefaultDocumentFormatRegistry.PPT;
+ }
+ },
+
+ /**
+ * 演示文稿pptx格式
+ */
+ PPTX {
+ @Override
+ public DocumentFormat getFormFormat() {
+ return DefaultDocumentFormatRegistry.PPTX;
+ }
+ },
+
+ /**
+ * 电子表格xls格式
+ */
+ XLS {
+ @Override
+ public DocumentFormat getFormFormat() {
+ return DefaultDocumentFormatRegistry.XLS;
+ }
+
+ @Override
+ public DocumentFormat getTargetFormat() {
+ return DefaultDocumentFormatRegistry.HTML;
+ }
+ },
+
+ /**
+ * 电子表格xlsx格式
+ */
+ XLSX {
+ @Override
+ public DocumentFormat getFormFormat() {
+ return DefaultDocumentFormatRegistry.XLSX;
+ }
+
+ @Override
+ public DocumentFormat getTargetFormat() {
+ return DefaultDocumentFormatRegistry.HTML;
+ }
+ },
+
+ /**
+ * 文本txt格式
+ */
+ TXT {
+ @Override
+ public DocumentFormat getFormFormat() {
+ return DefaultDocumentFormatRegistry.TXT;
+ }
+ };
+
+ public InputStream getInputStream(InputStream inputStream) throws IOException {
+ return inputStream;
+ }
+
+ public abstract DocumentFormat getFormFormat();
+
+ public DocumentFormat getTargetFormat() {
+ return DefaultDocumentFormatRegistry.PDF;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/LogAnnotionOpTypeEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/LogAnnotionOpTypeEnum.java
new file mode 100644
index 00000000..c38b7a1c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/LogAnnotionOpTypeEnum.java
@@ -0,0 +1,107 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 日志注解操作类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 17:45
+ */
+@Getter
+public enum LogAnnotionOpTypeEnum {
+
+ /**
+ * 其它
+ */
+ OTHER,
+
+ /**
+ * 增加
+ */
+ ADD,
+
+ /**
+ * 删除
+ */
+ DELETE,
+
+ /**
+ * 编辑
+ */
+ EDIT,
+
+ /**
+ * 更新
+ */
+ UPDATE,
+
+ /**
+ * 查询
+ */
+ QUERY,
+
+ /**
+ * 详情
+ */
+ DETAIL,
+
+ /**
+ * 树
+ */
+ TREE,
+
+ /**
+ * 导入
+ */
+ IMPORT,
+
+ /**
+ * 导出
+ */
+ EXPORT,
+
+ /**
+ * 授权
+ */
+ GRANT,
+
+ /**
+ * 强退
+ */
+ FORCE,
+
+ /**
+ * 清空
+ */
+ CLEAN,
+
+ /**
+ * 修改状态
+ */
+ CHANGE_STATUS
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/LogicTypeEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/LogicTypeEnum.java
new file mode 100644
index 00000000..2cb1f2b0
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/LogicTypeEnum.java
@@ -0,0 +1,44 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.enums;
+
+/**
+ * 逻辑枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 10:23
+ */
+public enum LogicTypeEnum {
+
+ /**
+ * 与
+ */
+ AND,
+
+ /**
+ * 或
+ */
+ OR
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/YesOrNotEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/YesOrNotEnum.java
new file mode 100644
index 00000000..b938a107
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/enums/YesOrNotEnum.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 是或否的枚举
+ *
+ * @author yubaoshan
+ * @date 2020/4/13 22:59
+ */
+@Getter
+public enum YesOrNotEnum {
+
+ /**
+ * 是
+ */
+ Y("Y", "是"),
+
+ /**
+ * 否
+ */
+ N("N", "否");
+
+ private final String code;
+
+ private final String message;
+
+ YesOrNotEnum(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/AuthException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/AuthException.java
new file mode 100644
index 00000000..b69fa04f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/AuthException.java
@@ -0,0 +1,54 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception;
+
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import lombok.Getter;
+
+/**
+ * 认证相关的异常
+ *
+ * 认证和鉴权的区别:
+ *
+ * 认证可以证明你能登录系统,认证的过程是校验token的过程
+ * 鉴权可以证明你有系统的哪些权限,鉴权的过程是校验角色是否包含某些接口的权限
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 9:55
+ */
+@Getter
+public class AuthException extends RuntimeException {
+
+ private final Integer code;
+
+ private final String errorMessage;
+
+ public AuthException(AbstractBaseExceptionEnum exception) {
+ super(exception.getMessage());
+ this.code = exception.getCode();
+ this.errorMessage = exception.getMessage();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/DemoException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/DemoException.java
new file mode 100644
index 00000000..faa0a657
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/DemoException.java
@@ -0,0 +1,46 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception;
+
+import lombok.Getter;
+
+/**
+ * 演示环境,无法操作的异常
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 12:22
+ */
+@Getter
+public class DemoException extends ServiceException {
+
+ private static final int DEMO_EXP_CODE = 14000;
+
+ private static final String DEMO_EXP_ERROR_MESSAGE = "演示环境,无法操作!";
+
+ public DemoException() {
+ super(DEMO_EXP_CODE, DEMO_EXP_ERROR_MESSAGE);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/LibreOfficeException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/LibreOfficeException.java
new file mode 100644
index 00000000..432cd274
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/LibreOfficeException.java
@@ -0,0 +1,46 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception;
+
+import lombok.Getter;
+
+/**
+ * LibreOffice相关异常
+ *
+ * @author xuyuxiang
+ * @date 2020/7/7 11:08
+ */
+@Getter
+public class LibreOfficeException extends ServiceException {
+
+ private static final int LIBRE_OFFICE_EXP_CODE = 15000;
+
+ private static final String LIBRE_OFFICE_EXP_ERROR_MESSAGE = "LibreOffice初始化异常,请检查LibreOffice是否启动!";
+
+ public LibreOfficeException() {
+ super(LIBRE_OFFICE_EXP_CODE, LIBRE_OFFICE_EXP_ERROR_MESSAGE);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/PermissionException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/PermissionException.java
new file mode 100644
index 00000000..ffbb7472
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/PermissionException.java
@@ -0,0 +1,55 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception;
+
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import lombok.Getter;
+
+/**
+ * 授权和鉴权异常
+ *
+ * 认证和鉴权的区别:
+ *
+ * 认证可以证明你能登录系统,认证的过程是校验token的过程
+ * 鉴权可以证明你有系统的哪些权限,鉴权的过程是校验角色是否包含某些接口的权限
+ * 也包含当前用户是否有操作该数据的权限
+ *
+ * @author yubaoshan
+ * @date 2019/7/18 22:18
+ */
+@Getter
+public class PermissionException extends RuntimeException {
+
+ private final Integer code;
+
+ private final String errorMessage;
+
+ public PermissionException(AbstractBaseExceptionEnum exception) {
+ super(exception.getMessage());
+ this.code = exception.getCode();
+ this.errorMessage = exception.getMessage();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/RequestMethodException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/RequestMethodException.java
new file mode 100644
index 00000000..9ae798a8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/RequestMethodException.java
@@ -0,0 +1,48 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception;
+
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import lombok.Getter;
+
+/**
+ * 请求方法异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 15:35
+ */
+@Getter
+public class RequestMethodException extends RuntimeException {
+
+ private final Integer code;
+
+ private final String errorMessage;
+
+ public RequestMethodException(AbstractBaseExceptionEnum exception) {
+ super(exception.getMessage());
+ this.code = exception.getCode();
+ this.errorMessage = exception.getMessage();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/ServiceException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/ServiceException.java
new file mode 100644
index 00000000..80923f99
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/ServiceException.java
@@ -0,0 +1,56 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception;
+
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 业务异常
+ *
+ * @author xuyuxiang
+ * @date 2020/4/8 15:54
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ServiceException extends RuntimeException {
+
+ private Integer code;
+
+ private String errorMessage;
+
+ public ServiceException(Integer code, String errorMessage) {
+ super(errorMessage);
+ this.code = code;
+ this.errorMessage = errorMessage;
+ }
+
+ public ServiceException(AbstractBaseExceptionEnum exception) {
+ super(exception.getMessage());
+ this.code = exception.getCode();
+ this.errorMessage = exception.getMessage();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/AuthExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/AuthExceptionEnum.java
new file mode 100644
index 00000000..623221ff
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/AuthExceptionEnum.java
@@ -0,0 +1,110 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 认证相关的异常的枚举
+ *
+ * 认证和鉴权的区别:
+ *
+ * 认证可以证明你能登录系统,认证的过程是校验token的过程
+ * 鉴权可以证明你有系统的哪些权限,鉴权的过程是校验角色是否包含某些接口的权限
+ *
+ * @author yubaoshan
+ * @date 2019/7/18 22:22
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.AUTH_EXCEPTION_ENUM)
+public enum AuthExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 账号或密码为空
+ */
+ ACCOUNT_PWD_EMPTY(1, "账号或密码为空,请检查account或password参数"),
+
+ /**
+ * 账号密码错误
+ */
+ ACCOUNT_PWD_ERROR(2, "账号或密码错误,请检查account或password参数"),
+
+ /**
+ * 验证码错误
+ */
+ VALID_CODE_ERROR(3, "验证码错误,请检查captcha参数"),
+
+ /**
+ * 请求token为空
+ */
+ REQUEST_TOKEN_EMPTY(4, "请求token为空,请携带token访问本接口"),
+
+ /**
+ * token格式不正确,token请以Bearer开头
+ */
+ NOT_VALID_TOKEN_TYPE(5, "token格式不正确,token请以Bearer开头,并且Bearer后边带一个空格"),
+
+ /**
+ * 请求token错误
+ */
+ REQUEST_TOKEN_ERROR(6, "请求token错误"),
+
+ /**
+ * 账号被冻结
+ */
+ ACCOUNT_FREEZE_ERROR(7, "账号被冻结,请联系管理员"),
+
+ /**
+ * 登录已过期
+ */
+ LOGIN_EXPIRED(8, "登录已过期,请重新登录"),
+
+ /**
+ * 无登录用户
+ */
+ NO_LOGIN_USER(9, "无登录用户");
+
+ private final Integer code;
+
+ private final String message;
+
+ AuthExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/ParamExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/ParamExceptionEnum.java
new file mode 100644
index 00000000..fc6bc0d7
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/ParamExceptionEnum.java
@@ -0,0 +1,64 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 参数校验异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/25 20:11
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.PARAM_EXCEPTION_ENUM)
+public enum ParamExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 参数错误
+ */
+ PARAM_ERROR(1, "参数错误");
+
+ private final Integer code;
+
+ private final String message;
+
+ ParamExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/PermissionExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/PermissionExceptionEnum.java
new file mode 100644
index 00000000..77075658
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/PermissionExceptionEnum.java
@@ -0,0 +1,83 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 授权和鉴权异常的枚举
+ *
+ * 认证和鉴权的区别:
+ *
+ * 认证可以证明你能登录系统,认证的过程是校验token的过程
+ * 鉴权可以证明你有系统的哪些权限,鉴权的过程是校验角色是否包含某些接口的权限
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 10:14
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.PERMISSION_EXCEPTION_ENUM)
+public enum PermissionExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 资源路径不存在
+ */
+ URL_NOT_EXIST(1, "资源路径不存在,请检查请求地址"),
+
+ /**
+ * 没有权限访问资源
+ */
+ NO_PERMISSION(2, "没有权限访问资源,请联系管理员"),
+
+ /**
+ * 没有权限操作该数据
+ */
+ NO_PERMISSION_OPERATE(3, "没有权限操作该数据,请联系管理员");
+
+ private final Integer code;
+
+ private final String message;
+
+ PermissionExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/RequestMethodExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/RequestMethodExceptionEnum.java
new file mode 100644
index 00000000..db2a55e8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/RequestMethodExceptionEnum.java
@@ -0,0 +1,73 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 请求方法相关异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 15:33
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.REQUEST_METHOD_EXCEPTION_ENUM)
+public enum RequestMethodExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 不支持该请求方法,请求方法应为POST
+ */
+ REQUEST_METHOD_IS_POST(1, "不支持该请求方法,请求方法应为POST"),
+
+ /**
+ * 不支持该请求方法,请求方法应为GET
+ */
+ REQUEST_METHOD_IS_GET(2, "不支持该请求方法,请求方法应为GET");
+
+ private final Integer code;
+
+ private final String message;
+
+ RequestMethodExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/RequestTypeExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/RequestTypeExceptionEnum.java
new file mode 100644
index 00000000..ea25e3b2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/RequestTypeExceptionEnum.java
@@ -0,0 +1,73 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 请求类型相关异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/4/2 15:42
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.REQUEST_TYPE_EXCEPTION_ENUM)
+public enum RequestTypeExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 参数传递格式不支持
+ */
+ REQUEST_TYPE_IS_JSON(1, "参数传递格式不支持,请使用JSON格式传参"),
+
+ /**
+ * 请求JSON参数格式不正确
+ */
+ REQUEST_JSON_ERROR(2, "请求JSON参数格式不正确,请检查参数格式");
+
+ private final Integer code;
+
+ private final String message;
+
+ RequestTypeExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/ServerExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/ServerExceptionEnum.java
new file mode 100644
index 00000000..9c2ad4cc
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/ServerExceptionEnum.java
@@ -0,0 +1,78 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 服务器内部相关异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:19
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.SERVER_EXCEPTION_ENUM)
+public enum ServerExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 当前请求参数为空或数据缺失
+ */
+ REQUEST_EMPTY(1, "当前请求参数为空或数据缺失,请联系管理员"),
+
+ /**
+ * 服务器出现未知异常
+ */
+ SERVER_ERROR(2, "服务器出现异常,请联系管理员"),
+
+ /**
+ * 常量获取存在空值
+ */
+ CONSTANT_EMPTY(3, "常量获取存在空值,请检查sys_config中是否配置");
+
+ private final Integer code;
+
+ private final String message;
+
+ ServerExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/StatusExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/StatusExceptionEnum.java
new file mode 100644
index 00000000..00d3b6cb
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/StatusExceptionEnum.java
@@ -0,0 +1,78 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 状态枚举
+ *
+ * @author yubaoshan
+ * @date 2020/4/30 22:45
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.STATUS_EXCEPTION_ENUM)
+public enum StatusExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 请求状态值为空
+ */
+ REQUEST_EMPTY(1, "请求状态值为空"),
+
+ /**
+ * 请求状值为非正确状态值
+ */
+ NOT_WRITE_STATUS(2, "请求状态值不合法"),
+
+ /**
+ * 更新状态失败,试图更新被删除的记录
+ */
+ UPDATE_STATUS_ERROR(3, "更新状态失败,您试图更新被删除的记录");
+
+ private final Integer code;
+
+ private final String message;
+
+ StatusExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/WrapperExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/WrapperExceptionEnum.java
new file mode 100644
index 00000000..6f3e8372
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/WrapperExceptionEnum.java
@@ -0,0 +1,78 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.consts.ExpEnumConstant;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+
+/**
+ * 对象包装异常
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 14:36
+ */
+@ExpEnumType(module = ExpEnumConstant.XIAONUO_CORE_MODULE_EXP_CODE, kind = ExpEnumConstant.WRAPPER_EXCEPTION_ENUM)
+public enum WrapperExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 被包装的值不能是基本类型
+ */
+ BASIC_TYPE_ERROR(1, "被包装的值不能是基本类型"),
+
+ /**
+ * 获取转化字段的值异常
+ */
+ TRANSFER_FILED_VALUE_ERROR(2, "获取转化字段的值异常"),
+
+ /**
+ * 字段包装转化异常
+ */
+ TRANSFER_ERROR(3, "字段包装转化异常");
+
+ private final Integer code;
+
+ private final String message;
+
+ WrapperExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/abs/AbstractBaseExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/abs/AbstractBaseExceptionEnum.java
new file mode 100644
index 00000000..4b11a7b3
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/exception/enums/abs/AbstractBaseExceptionEnum.java
@@ -0,0 +1,53 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.exception.enums.abs;
+
+/**
+ * 异常枚举格式规范
+ *
+ * @author yubaoshan
+ * @date 2017/12/17 22:22
+ */
+public interface AbstractBaseExceptionEnum {
+
+ /**
+ * 获取异常的状态码
+ *
+ * @return 状态码
+ * @author yubaoshan
+ * @date 2020/7/9 14:28
+ */
+ Integer getCode();
+
+ /**
+ * 获取异常的提示信息
+ *
+ * @return 提示信息
+ * @author yubaoshan
+ * @date 2020/7/9 14:28
+ */
+ String getMessage();
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/ExpEnumCodeFactory.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/ExpEnumCodeFactory.java
new file mode 100644
index 00000000..225d2ac3
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/ExpEnumCodeFactory.java
@@ -0,0 +1,54 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.factory;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+
+/**
+ * 异常枚举code值快速创建
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 21:30
+ */
+public class ExpEnumCodeFactory {
+
+ public static Integer getExpEnumCode(Class> clazz, int code) {
+
+ // 默认的异常响应码
+ Integer defaultCode = Integer.valueOf("" + 99 + 9999 + 9);
+
+ if (clazz == null) {
+ return defaultCode;
+ } else {
+ ExpEnumType expEnumType = clazz.getAnnotation(ExpEnumType.class);
+ if (expEnumType == null) {
+ return defaultCode;
+ }
+ return Integer.valueOf("" + expEnumType.module() + expEnumType.kind() + code);
+ }
+
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/PageFactory.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/PageFactory.java
new file mode 100644
index 00000000..7ebae420
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/PageFactory.java
@@ -0,0 +1,80 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.factory;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * 默认分页参数构建
+ *
+ * @author yubaoshan
+ * @date 2017/11/15 13:52
+ */
+public class PageFactory {
+
+ /**
+ * 每页大小(默认20)
+ */
+ private static final String PAGE_SIZE_PARAM_NAME = "pageSize";
+
+ /**
+ * 第几页(从1开始)
+ */
+ private static final String PAGE_NO_PARAM_NAME = "pageNo";
+
+ /**
+ * 默认分页,在使用时PageFactory.defaultPage会自动获取pageSize和pageNo参数
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 16:42
+ */
+ public static Page defaultPage() {
+
+ int pageSize = 20;
+ int pageNo = 1;
+
+ HttpServletRequest request = HttpServletUtil.getRequest();
+
+ //每页条数
+ String pageSizeString = request.getParameter(PAGE_SIZE_PARAM_NAME);
+ if (ObjectUtil.isNotEmpty(pageSizeString)) {
+ pageSize = Integer.parseInt(pageSizeString);
+ }
+
+ //第几页
+ String pageNoString = request.getParameter(PAGE_NO_PARAM_NAME);
+ if (ObjectUtil.isNotEmpty(pageNoString)) {
+ pageNo = Integer.parseInt(pageNoString);
+ }
+
+ return new Page<>(pageNo, pageSize);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/TreeBuildFactory.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/TreeBuildFactory.java
new file mode 100644
index 00000000..49001a8b
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/factory/TreeBuildFactory.java
@@ -0,0 +1,128 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.factory;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.pojo.base.node.BaseTreeNode;
+import com.cn.xiaonuo.core.pojo.base.node.BaseTreeNode;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 默认递归工具类,用于遍历有父子关系的节点,例如菜单树,字典树等等
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 14:17
+ */
+@Data
+public class TreeBuildFactory {
+
+ /**
+ * 顶级节点的父节点id(默认0)
+ */
+ private Long rootParentId = 0L;
+
+ /**
+ * 树节点构造
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 14:09
+ */
+ public List doTreeBuild(List nodes) {
+
+ //具体构建的过程
+ List buildComplete = this.executeBuilding(nodes);
+
+ //构建之后的处理工作
+ return this.afterBuild(buildComplete);
+ }
+
+ /**
+ * 查询子节点集合
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 14:10
+ */
+ private void buildChildNodes(List totalNodes, T node, List childNodeLists) {
+ if (ObjectUtil.hasEmpty(totalNodes, node)) {
+ return;
+ }
+ List nodeSubLists = this.getSubChildLevelOne(totalNodes, node);
+ if (ObjectUtil.isNotEmpty(nodeSubLists)) {
+ nodeSubLists.forEach(t -> this.buildChildNodes(totalNodes, t, CollectionUtil.newArrayList()));
+ }
+ childNodeLists.addAll(nodeSubLists);
+ node.setChildren(childNodeLists);
+ }
+
+ /**
+ * 获取子一级节点的集合
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 14:12
+ */
+ private List getSubChildLevelOne(List list, T node) {
+ List nodeList = CollectionUtil.newArrayList();
+ if (ObjectUtil.isNotEmpty(list)) {
+ list.forEach(t -> {
+ if (t.getPid().equals(node.getId())) {
+ nodeList.add(t);
+ }
+ });
+ }
+ return nodeList;
+ }
+
+ /**
+ * 执行构造
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 14:13
+ */
+ private List executeBuilding(List nodes) {
+ nodes.forEach(t -> this.buildChildNodes(nodes, t, CollectionUtil.newArrayList()));
+ return nodes;
+ }
+
+ /**
+ * 构造之后
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 14:13
+ */
+ private List afterBuild(List nodes) {
+ //去掉所有的二级节点
+ ArrayList results = CollectionUtil.newArrayList();
+ nodes.forEach(t -> {
+ if (rootParentId.equals(t.getPid())) {
+ results.add(t);
+ }
+ });
+ return results;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/FileOperator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/FileOperator.java
new file mode 100644
index 00000000..a964f1ed
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/FileOperator.java
@@ -0,0 +1,147 @@
+package com.cn.xiaonuo.core.file;
+
+
+import com.cn.xiaonuo.core.file.common.enums.BucketAuthEnum;
+
+import java.io.InputStream;
+
+/**
+ * 文件操纵者(内网操作)
+ *
+ * 如果存在未包含的操作,可以调用getClient()自行获取client进行操作
+ *
+ * @author xuyuxiang
+ * @date 2018-06-27-下午12:37
+ */
+public interface FileOperator {
+
+ /**
+ * 初始化操作的客户端
+ *
+ * @author xuyuxiang
+ * @date 2020/5/23 2:32 下午
+ */
+ void initClient();
+
+ /**
+ * 销毁操作的客户端
+ *
+ * @author xuyuxiang
+ * @date 2020/5/23 2:32 下午
+ */
+ void destroyClient();
+
+ /**
+ * 获取操作的客户端
+ *
+ * @author xuyuxiang
+ * @date 2020/5/23 2:58 下午
+ */
+ Object getClient();
+
+ /**
+ * 查询存储桶是否存在
+ *
+ * 例如:传入参数examplebucket-1250000000,返回true代表存在此桶
+ *
+ * @author xuyuxiang
+ * @date 2020/5/23 2:29 下午
+ */
+ boolean doesBucketExist(String bucketName);
+
+ /**
+ * 设置预定义策略
+ *
+ * 预定义策略如公有读、公有读写、私有读
+ *
+ * @author xuyuxiang
+ * @date 2020/5/23 3:02 下午
+ */
+ void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum);
+
+ /**
+ * 判断是否存在文件
+ *
+ * @param bucketName 桶名称
+ * @param key 唯一标示id,例如a.txt, doc/a.txt
+ * @author xuyuxiang
+ * @date 2018/6/27 下午1:14
+ */
+ boolean isExistingFile(String bucketName, String key);
+
+ /**
+ * 存储文件
+ *
+ * @param bucketName 桶名称
+ * @param key 唯一标示id,例如a.txt, doc/a.txt
+ * @param bytes 文件字节数组
+ * @author xuyuxiang
+ * @date 2018/6/27 下午1:16
+ */
+ void storageFile(String bucketName, String key, byte[] bytes);
+
+ /**
+ * 存储文件(存放到指定的bucket里边)
+ *
+ * @param bucketName 桶名称
+ * @param key 唯一标示id,例如a.txt, doc/a.txt
+ * @param inputStream 文件流
+ * @author xuyuxiang
+ * @date 2018年10月19日13:20:37
+ */
+ void storageFile(String bucketName, String key, InputStream inputStream);
+
+ /**
+ * 获取某个bucket下的文件字节
+ *
+ * @param bucketName 桶名称
+ * @param key 唯一标示id,例如a.txt, doc/a.txt
+ * @author xuyuxiang
+ * @date 2018/6/27 下午1:15
+ */
+ byte[] getFileBytes(String bucketName, String key);
+
+ /**
+ * 文件访问权限管理
+ *
+ * @param bucketName 桶名称
+ * @param key 唯一标示id,例如a.txt, doc/a.txt
+ * @param bucketAuthEnum 文件权限
+ * @author xuyuxiang
+ * @date 2020/5/23 5:30 下午
+ */
+ void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum);
+
+ /**
+ * 拷贝文件
+ *
+ * @param originBucketName 源文件桶
+ * @param originFileKey 源文件名称
+ * @param newBucketName 新文件桶
+ * @param newFileKey 新文件名称
+ * @author xuyuxiang
+ * @date 2020/5/23 6:09 下午
+ */
+ void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey);
+
+ /**
+ * 获取文件的下载地址(带鉴权的),生成外网地址
+ *
+ * @param bucketName 文件桶
+ * @param key 文件唯一标识
+ * @author xuyuxiang
+ * @date 2018/7/7 上午11:27
+ */
+ String getFileAuthUrl(String bucketName, String key, Long timeoutMillis);
+
+ /**
+ * 删除文件
+ *
+ * @param bucketName 文件桶
+ * @param key 文件唯一标识
+ * @author xuyuxiang
+ * @date 2020/9/18
+ */
+ void deleteFile(String bucketName, String key);
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/common/enums/BucketAuthEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/common/enums/BucketAuthEnum.java
new file mode 100644
index 00000000..b62cdee6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/common/enums/BucketAuthEnum.java
@@ -0,0 +1,26 @@
+package com.cn.xiaonuo.core.file.common.enums;
+
+/**
+ * 桶的权限策略枚举
+ *
+ * @author xuyuxiang
+ * @date 2020-05-23-3:03 下午
+ */
+public enum BucketAuthEnum {
+
+ /**
+ * 私有的(仅有 owner 可以读写)
+ */
+ PRIVATE,
+
+ /**
+ * 公有读,私有写( owner 可以读写, 其他客户可以读)
+ */
+ PUBLIC_READ,
+
+ /**
+ * 公共读写(即所有人都可以读写,慎用)
+ */
+ PUBLIC_READ_WRITE
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/common/exp/FileServiceException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/common/exp/FileServiceException.java
new file mode 100644
index 00000000..572c7810
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/common/exp/FileServiceException.java
@@ -0,0 +1,18 @@
+package com.cn.xiaonuo.core.file.common.exp;
+
+import lombok.Getter;
+
+/**
+ * 文件操作业务异常
+ *
+ * @author xuyuxiang
+ * @date 2020-05-23-2:42 下午
+ */
+@Getter
+public class FileServiceException extends RuntimeException {
+
+ public FileServiceException(String message) {
+ super(message);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/AliyunFileOperator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/AliyunFileOperator.java
new file mode 100644
index 00000000..a09fca8d
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/AliyunFileOperator.java
@@ -0,0 +1,189 @@
+package com.cn.xiaonuo.core.file.modular.aliyun;
+
+import cn.hutool.core.io.IoUtil;
+import com.aliyun.oss.ClientException;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.OSSException;
+import com.aliyun.oss.model.CannedAccessControlList;
+import com.aliyun.oss.model.OSSObject;
+import com.aliyun.oss.model.PutObjectRequest;
+import com.cn.xiaonuo.core.file.FileOperator;
+import com.cn.xiaonuo.core.file.common.enums.BucketAuthEnum;
+import com.cn.xiaonuo.core.file.modular.aliyun.exp.AliyunFileServiceException;
+import com.cn.xiaonuo.core.file.modular.aliyun.prop.AliyunOssProperties;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Date;
+
+/**
+ * 阿里云文件操作
+ *
+ * @author xuyuxiang
+ * @date 2020/5/25 2:33 下午
+ */
+public class AliyunFileOperator implements FileOperator {
+
+ /**
+ * 阿里云文件操作客户端
+ */
+ private OSS ossClient;
+
+ /**
+ * 阿里云oss的配置
+ */
+ private final AliyunOssProperties aliyunOssProperties;
+
+ public AliyunFileOperator(AliyunOssProperties aliyunOssProperties) {
+ this.aliyunOssProperties = aliyunOssProperties;
+ this.initClient();
+ }
+
+ @Override
+ public void initClient() {
+ String endpoint = aliyunOssProperties.getEndPoint();
+ String accessKeyId = aliyunOssProperties.getAccessKeyId();
+ String accessKeySecret = aliyunOssProperties.getAccessKeySecret();
+
+ // 创建OSSClient实例。
+ ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+ }
+
+ @Override
+ public void destroyClient() {
+ ossClient.shutdown();
+ }
+
+ @Override
+ public Object getClient() {
+ return ossClient;
+ }
+
+ @Override
+ public boolean doesBucketExist(String bucketName) {
+ try {
+ return ossClient.doesBucketExist(bucketName);
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {
+ try {
+ if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {
+ ossClient.setBucketAcl(bucketName, CannedAccessControlList.Private);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {
+ ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {
+ ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);
+ }
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public boolean isExistingFile(String bucketName, String key) {
+ try {
+ return ossClient.doesObjectExist(bucketName, key);
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public void storageFile(String bucketName, String key, byte[] bytes) {
+ try {
+ ossClient.putObject(bucketName, key, new ByteArrayInputStream(bytes));
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public void storageFile(String bucketName, String key, InputStream inputStream) {
+ try {
+ PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream);
+ ossClient.putObject(putObjectRequest);
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public byte[] getFileBytes(String bucketName, String key) {
+ InputStream objectContent = null;
+ try {
+ OSSObject ossObject = ossClient.getObject(bucketName, key);
+ objectContent = ossObject.getObjectContent();
+ return IoUtil.readBytes(objectContent);
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ } finally {
+ IoUtil.close(objectContent);
+ }
+
+ }
+
+ @Override
+ public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {
+ try {
+ if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {
+ ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.Private);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {
+ ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {
+ ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicReadWrite);
+ }
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
+ try {
+ ossClient.copyObject(originBucketName, originFileKey, newBucketName, newFileKey);
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {
+ try {
+ Date expiration = new Date(new Date().getTime() + timeoutMillis);
+ URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
+ return url.toString();
+ } catch (OSSException e) {
+ throw new AliyunFileServiceException(e);
+ } catch (ClientException e) {
+ throw new AliyunFileServiceException(e);
+ }
+ }
+
+ @Override
+ public void deleteFile(String bucketName, String key) {
+ ossClient.deleteObject(bucketName, key);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/exp/AliyunFileServiceException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/exp/AliyunFileServiceException.java
new file mode 100644
index 00000000..91fafaf2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/exp/AliyunFileServiceException.java
@@ -0,0 +1,46 @@
+package com.cn.xiaonuo.core.file.modular.aliyun.exp;
+
+import com.aliyun.oss.ClientException;
+import com.aliyun.oss.OSSException;
+import lombok.Getter;
+
+/**
+ * 腾讯文件操作异常
+ *
+ * @author xuyuxiang
+ * @date 2020-05-23-2:42 下午
+ */
+@Getter
+public class AliyunFileServiceException extends RuntimeException {
+
+ /**
+ * 客户端异常
+ *
+ * 是由于客户端原因导致无法和服务端完成正常的交互而导致的失败,如客户端无法连接到服务端,无法解析服务端返回的数据
+ */
+ private ClientException clientException;
+
+ /**
+ * 服务端异常
+ *
+ * 用于指交互正常完成,但是操作失败的场景
+ *
+ * 例如客户端访问一个不存在 Bucket,删除一个不存在的文件,没有权限进行某个操作, 服务端故障异常等
+ */
+ private OSSException ossException;
+
+ public AliyunFileServiceException(String message) {
+ super(message);
+ }
+
+ public AliyunFileServiceException(ClientException clientException) {
+ super(clientException.getMessage());
+ this.clientException = clientException;
+ }
+
+ public AliyunFileServiceException(OSSException ossException) {
+ super(ossException.getMessage());
+ this.ossException = ossException;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/prop/AliyunOssProperties.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/prop/AliyunOssProperties.java
new file mode 100644
index 00000000..e6f64c45
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/aliyun/prop/AliyunOssProperties.java
@@ -0,0 +1,31 @@
+package com.cn.xiaonuo.core.file.modular.aliyun.prop;
+
+import lombok.Data;
+
+/**
+ * 腾讯云cos文件存储配置
+ *
+ * @author xuyuxiang
+ * @date 2020/5/22 6:56 下午
+ */
+@Data
+public class AliyunOssProperties {
+
+ /**
+ * 默认北京,内网
+ *
+ * https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.17.467f45dcjB4WQQ#concept-zt4-cvy-5db
+ */
+ private String endPoint = "http://oss-cn-beijing.aliyuncs.com";
+
+ /**
+ * 秘钥id
+ */
+ private String accessKeyId;
+
+ /**
+ * 秘钥secret
+ */
+ private String accessKeySecret;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/local/LocalFileOperator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/local/LocalFileOperator.java
new file mode 100644
index 00000000..200f092f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/local/LocalFileOperator.java
@@ -0,0 +1,157 @@
+package com.cn.xiaonuo.core.file.modular.local;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.system.SystemUtil;
+import com.cn.xiaonuo.core.file.FileOperator;
+import com.cn.xiaonuo.core.file.common.enums.BucketAuthEnum;
+import com.cn.xiaonuo.core.file.common.exp.FileServiceException;
+import com.cn.xiaonuo.core.file.modular.local.prop.LocalFileProperties;
+
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * 阿里云文件操作
+ *
+ * @author xuyuxiang
+ * @date 2020/5/25 2:33 下午
+ */
+public class LocalFileOperator implements FileOperator {
+
+ private final LocalFileProperties localFileProperties;
+
+ private String currentSavePath = "";
+
+ public LocalFileOperator(LocalFileProperties localFileProperties) {
+ this.localFileProperties = localFileProperties;
+ initClient();
+ }
+
+ @Override
+ public void initClient() {
+ if (SystemUtil.getOsInfo().isWindows()) {
+ String savePathWindows = localFileProperties.getLocalFileSavePathWin();
+ if (!FileUtil.exist(savePathWindows)) {
+ FileUtil.mkdir(savePathWindows);
+ }
+ currentSavePath = savePathWindows;
+ } else {
+ String savePathLinux = localFileProperties.getLocalFileSavePathLinux();
+ if (!FileUtil.exist(savePathLinux)) {
+ FileUtil.mkdir(savePathLinux);
+ }
+ currentSavePath = savePathLinux;
+ }
+ }
+
+ @Override
+ public void destroyClient() {
+ // empty
+ }
+
+ @Override
+ public Object getClient() {
+ // empty
+ return null;
+ }
+
+ @Override
+ public boolean doesBucketExist(String bucketName) {
+ String absolutePath = currentSavePath + File.separator + bucketName;
+ return FileUtil.exist(absolutePath);
+ }
+
+ @Override
+ public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {
+ // empty
+ }
+
+ @Override
+ public boolean isExistingFile(String bucketName, String key) {
+ String absoluteFile = currentSavePath + File.separator + bucketName + File.separator + key;
+ return FileUtil.exist(absoluteFile);
+ }
+
+ @Override
+ public void storageFile(String bucketName, String key, byte[] bytes) {
+
+ // 判断bucket存在不存在
+ String bucketPath = currentSavePath + File.separator + bucketName;
+ if (!FileUtil.exist(bucketPath)) {
+ FileUtil.mkdir(bucketPath);
+ }
+
+ // 存储文件
+ String absoluteFile = currentSavePath + File.separator + bucketName + File.separator + key;
+ FileUtil.writeBytes(bytes, absoluteFile);
+ }
+
+ @Override
+ public void storageFile(String bucketName, String key, InputStream inputStream) {
+
+ // 判断bucket存在不存在
+ String bucketPath = currentSavePath + File.separator + bucketName;
+ if (!FileUtil.exist(bucketPath)) {
+ FileUtil.mkdir(bucketPath);
+ }
+
+ // 存储文件
+ String absoluteFile = currentSavePath + File.separator + bucketName + File.separator + key;
+ FileUtil.writeFromStream(inputStream, absoluteFile);
+ }
+
+ @Override
+ public byte[] getFileBytes(String bucketName, String key) {
+
+ // 判断文件存在不存在
+ String absoluteFile = currentSavePath + File.separator + bucketName + File.separator + key;
+ if (!FileUtil.exist(absoluteFile)) {
+ String message = StrUtil.format("文件不存在,bucket={},key={}", bucketName, key);
+ throw new FileServiceException(message);
+ } else {
+ return FileUtil.readBytes(absoluteFile);
+ }
+ }
+
+ @Override
+ public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {
+ // empty
+ }
+
+ @Override
+ public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
+
+ // 判断文件存在不存在
+ String originFile = currentSavePath + File.separator + originBucketName + File.separator + originFileKey;
+ if (!FileUtil.exist(originFile)) {
+ String message = StrUtil.format("源文件不存在,bucket={},key={}", originBucketName, originFileKey);
+ throw new FileServiceException(message);
+ } else {
+
+ // 拷贝文件
+ String destFile = currentSavePath + File.separator + newBucketName + File.separator + newFileKey;
+ FileUtil.copy(originFile, destFile, true);
+ }
+ }
+
+ @Override
+ public String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {
+ // empty
+ return null;
+ }
+
+ @Override
+ public void deleteFile(String bucketName, String key) {
+
+ // 判断文件存在不存在
+ String file = currentSavePath + File.separator + bucketName + File.separator + key;
+ if (!FileUtil.exist(file)) {
+ return;
+ }
+
+ // 删除文件
+ FileUtil.del(file);
+
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/local/prop/LocalFileProperties.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/local/prop/LocalFileProperties.java
new file mode 100644
index 00000000..63404eea
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/local/prop/LocalFileProperties.java
@@ -0,0 +1,24 @@
+package com.cn.xiaonuo.core.file.modular.local.prop;
+
+import lombok.Data;
+
+/**
+ * 本地文件存储配置
+ *
+ * @author xuyuxiang
+ * @date 2020/6/7 22:30
+ */
+@Data
+public class LocalFileProperties {
+
+ /**
+ * 本地文件存储位置(linux)
+ */
+ private String localFileSavePathLinux = "/tmp/tempFilePath";
+
+ /**
+ * 本地文件存储位置(windows)
+ */
+ private String localFileSavePathWin = "D:\\tempFilePath";
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/TenFileOperator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/TenFileOperator.java
new file mode 100644
index 00000000..6f263d14
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/TenFileOperator.java
@@ -0,0 +1,238 @@
+package com.cn.xiaonuo.core.file.modular.tencent;
+
+import cn.hutool.core.io.IoUtil;
+import com.cn.xiaonuo.core.file.FileOperator;
+import com.cn.xiaonuo.core.file.common.enums.BucketAuthEnum;
+import com.cn.xiaonuo.core.file.modular.tencent.exp.TencentFileServiceException;
+import com.cn.xiaonuo.core.file.modular.tencent.prop.TenCosProperties;
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.exception.CosClientException;
+import com.qcloud.cos.exception.CosServiceException;
+import com.qcloud.cos.http.HttpMethodName;
+import com.qcloud.cos.model.*;
+import com.qcloud.cos.region.Region;
+import com.qcloud.cos.transfer.TransferManager;
+import com.qcloud.cos.transfer.TransferManagerConfiguration;
+
+import javax.activation.MimetypesFileTypeMap;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Date;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * 腾讯云内网文件操作
+ *
+ * @author xuyuxiang
+ * @date 2020-05-22-6:51 下午
+ */
+public class TenFileOperator implements FileOperator {
+
+ private final TenCosProperties tenCosProperties;
+
+ private COSClient cosClient;
+
+ private TransferManager transferManager;
+
+ public TenFileOperator(TenCosProperties tenCosProperties) {
+ this.tenCosProperties = tenCosProperties;
+ initClient();
+ }
+
+ @Override
+ public void initClient() {
+
+ // 1.初始化用户身份信息
+ String secretId = tenCosProperties.getSecretId();
+ String secretKey = tenCosProperties.getSecretKey();
+ COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
+
+ // 2.设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
+ Region region = new Region(tenCosProperties.getRegionId());
+ ClientConfig clientConfig = new ClientConfig(region);
+
+ // 3.生成 cos 客户端。
+ cosClient = new COSClient(cred, clientConfig);
+
+ // 4.线程池大小,建议在客户端与 COS 网络充足(例如使用腾讯云的 CVM,同地域上传 COS)的情况下,设置成16或32即可,可较充分的利用网络资源
+ // 对于使用公网传输且网络带宽质量不高的情况,建议减小该值,避免因网速过慢,造成请求超时。
+ ExecutorService threadPool = Executors.newFixedThreadPool(32);
+
+ // 5.传入一个 threadpool, 若不传入线程池,默认 TransferManager 中会生成一个单线程的线程池。
+ transferManager = new TransferManager(cosClient, threadPool);
+
+ // 6.设置高级接口的分块上传阈值和分块大小为10MB
+ TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
+ transferManagerConfiguration.setMultipartUploadThreshold(10 * 1024 * 1024);
+ transferManagerConfiguration.setMinimumUploadPartSize(10 * 1024 * 1024);
+ transferManager.setConfiguration(transferManagerConfiguration);
+ }
+
+ @Override
+ public void destroyClient() {
+ cosClient.shutdown();
+ }
+
+ @Override
+ public Object getClient() {
+ return cosClient;
+ }
+
+ @Override
+ public boolean doesBucketExist(String bucketName) {
+ try {
+ return cosClient.doesBucketExist(bucketName);
+ } catch (CosServiceException e) {
+ throw new TencentFileServiceException(e);
+ } catch (CosClientException e) {
+ throw new TencentFileServiceException(e);
+ }
+ }
+
+ @Override
+ public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {
+ try {
+ if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {
+ cosClient.setBucketAcl(bucketName, CannedAccessControlList.Private);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {
+ cosClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {
+ cosClient.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);
+ }
+ } catch (CosServiceException e) {
+ throw new TencentFileServiceException(e);
+ } catch (CosClientException e) {
+ throw new TencentFileServiceException(e);
+ }
+ }
+
+ @Override
+ public boolean isExistingFile(String bucketName, String key) {
+ try {
+ cosClient.getObjectMetadata(bucketName, key);
+ return true;
+ } catch (CosServiceException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void storageFile(String bucketName, String key, byte[] bytes) {
+ // 根据文件名获取contentType
+ String contentType = "application/octet-stream";
+ if (key.contains(".")) {
+ contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);
+ }
+
+ // 上传文件
+ ByteArrayInputStream byteArrayInputStream = null;
+ try {
+ byteArrayInputStream = new ByteArrayInputStream(bytes);
+ ObjectMetadata objectMetadata = new ObjectMetadata();
+ objectMetadata.setContentType(contentType);
+ cosClient.putObject(bucketName, key, new ByteArrayInputStream(bytes), objectMetadata);
+ } catch (CosServiceException e) {
+ throw new TencentFileServiceException(e);
+ } catch (CosClientException e) {
+ throw new TencentFileServiceException(e);
+ } finally {
+ IoUtil.close(byteArrayInputStream);
+ }
+
+ }
+
+ @Override
+ public void storageFile(String bucketName, String key, InputStream inputStream) {
+
+ // 根据文件名获取contentType
+ String contentType = "application/octet-stream";
+ if (key.contains(".")) {
+ contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);
+ }
+
+ // 上传文件
+ try {
+ ObjectMetadata objectMetadata = new ObjectMetadata();
+ objectMetadata.setContentType(contentType);
+ cosClient.putObject(bucketName, key, inputStream, objectMetadata);
+ } catch (CosServiceException e) {
+ throw new TencentFileServiceException(e);
+ } catch (CosClientException e) {
+ throw new TencentFileServiceException(e);
+ } finally {
+ IoUtil.close(inputStream);
+ }
+ }
+
+ @Override
+ public byte[] getFileBytes(String bucketName, String key) {
+ COSObjectInputStream cosObjectInput = null;
+ try {
+ GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
+ COSObject cosObject = cosClient.getObject(getObjectRequest);
+ cosObjectInput = cosObject.getObjectContent();
+ return IoUtil.readBytes(cosObjectInput);
+ } catch (CosServiceException e) {
+ throw new TencentFileServiceException(e);
+ } catch (CosClientException e) {
+ throw new TencentFileServiceException(e);
+ } finally {
+ IoUtil.close(cosObjectInput);
+ }
+ }
+
+ @Override
+ public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {
+ if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {
+ cosClient.setObjectAcl(bucketName, key, CannedAccessControlList.Private);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {
+ cosClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
+ } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {
+ cosClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicReadWrite);
+ }
+ }
+
+ @Override
+ public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
+ // 初始化拷贝参数
+ Region srcBucketRegion = new Region(tenCosProperties.getRegionId());
+ CopyObjectRequest copyObjectRequest = new CopyObjectRequest(
+ srcBucketRegion, originBucketName, originFileKey, newBucketName, newFileKey);
+
+ // 拷贝对象
+ try {
+ transferManager.copy(copyObjectRequest, cosClient, null);
+ } catch (CosServiceException e) {
+ throw new TencentFileServiceException(e);
+ } catch (CosClientException e) {
+ throw new TencentFileServiceException(e);
+ }
+ }
+
+ @Override
+ public String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {
+ GeneratePresignedUrlRequest presignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
+ Date expirationDate = new Date(System.currentTimeMillis() + timeoutMillis);
+ presignedUrlRequest.setExpiration(expirationDate);
+ URL url = null;
+ try {
+ url = cosClient.generatePresignedUrl(presignedUrlRequest);
+ } catch (CosServiceException e) {
+ throw new TencentFileServiceException(e);
+ } catch (CosClientException e) {
+ throw new TencentFileServiceException(e);
+ }
+ return url.toString();
+ }
+
+ @Override
+ public void deleteFile(String bucketName, String key) {
+ cosClient.deleteObject(bucketName, key);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/exp/TencentFileServiceException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/exp/TencentFileServiceException.java
new file mode 100644
index 00000000..ae08c2b5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/exp/TencentFileServiceException.java
@@ -0,0 +1,46 @@
+package com.cn.xiaonuo.core.file.modular.tencent.exp;
+
+import com.qcloud.cos.exception.CosClientException;
+import com.qcloud.cos.exception.CosServiceException;
+import lombok.Getter;
+
+/**
+ * 腾讯文件操作异常
+ *
+ * @author xuyuxiang
+ * @date 2020-05-23-2:42 下午
+ */
+@Getter
+public class TencentFileServiceException extends RuntimeException {
+
+ /**
+ * 客户端异常
+ *
+ * 是由于客户端原因导致无法和服务端完成正常的交互而导致的失败,如客户端无法连接到服务端,无法解析服务端返回的数据
+ */
+ private CosClientException cosClientException;
+
+ /**
+ * 服务端异常
+ *
+ * 用于指交互正常完成,但是操作失败的场景
+ *
+ * 例如客户端访问一个不存在 Bucket,删除一个不存在的文件,没有权限进行某个操作, 服务端故障异常等
+ */
+ private CosServiceException cosServiceException;
+
+ public TencentFileServiceException(String message) {
+ super(message);
+ }
+
+ public TencentFileServiceException(CosClientException cosClientException) {
+ super(cosClientException.getMessage());
+ this.cosClientException = cosClientException;
+ }
+
+ public TencentFileServiceException(CosServiceException cosServiceException) {
+ super(cosServiceException.getMessage());
+ this.cosServiceException = cosServiceException;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/prop/TenCosProperties.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/prop/TenCosProperties.java
new file mode 100644
index 00000000..d6891025
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/file/modular/tencent/prop/TenCosProperties.java
@@ -0,0 +1,29 @@
+package com.cn.xiaonuo.core.file.modular.tencent.prop;
+
+import lombok.Data;
+
+/**
+ * 腾讯云cos文件存储配置
+ *
+ * @author xuyuxiang
+ * @date 2020/5/22 6:56 下午
+ */
+@Data
+public class TenCosProperties {
+
+ /**
+ * secretId
+ */
+ private String secretId;
+
+ /**
+ * secretKey
+ */
+ private String secretKey;
+
+ /**
+ * 地域id(默认北京)
+ */
+ private String regionId = "ap-beijing";
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/entity/BaseEntity.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/entity/BaseEntity.java
new file mode 100644
index 00000000..875f1743
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/entity/BaseEntity.java
@@ -0,0 +1,69 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.base.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 通用基础字段,需要此通用字段的实体可继承此类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/10 16:02
+ */
+@Data
+public class BaseEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 创建时间
+ */
+ @TableField(fill = FieldFill.INSERT)
+ private Date createTime;
+
+ /**
+ * 创建人
+ */
+ @TableField(fill = FieldFill.INSERT)
+ private Long createUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField(fill = FieldFill.UPDATE)
+ private Date updateTime;
+
+ /**
+ * 更新人
+ */
+ @TableField(fill = FieldFill.UPDATE)
+ private Long updateUser;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/node/BaseTreeNode.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/node/BaseTreeNode.java
new file mode 100644
index 00000000..327c1384
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/node/BaseTreeNode.java
@@ -0,0 +1,64 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.base.node;
+
+import java.util.List;
+
+/**
+ * 树节点接口
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 14:07
+ */
+public interface BaseTreeNode {
+
+
+ /**
+ * 获取节点id
+ *
+ * @return 节点id
+ * @author xuyuxiang
+ * @date 2020/7/9 18:36
+ */
+ Long getId();
+
+ /**
+ * 获取节点父id
+ *
+ * @return 节点父id
+ * @author xuyuxiang
+ * @date 2020/7/9 18:36
+ */
+ Long getPid();
+
+ /**
+ * 设置children
+ *
+ * @param children 子节点集合
+ * @author xuyuxiang
+ * @date 2020/7/9 18:36
+ */
+ void setChildren(List children);
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/param/BaseParam.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/param/BaseParam.java
new file mode 100644
index 00000000..7ecfa2c0
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/param/BaseParam.java
@@ -0,0 +1,272 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.base.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 通用基础参数,相关实体参数校验可继承此类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/10 16:02
+ */
+@Data
+public class BaseParam implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 搜索值
+ */
+ private String searchValue;
+
+ /**
+ * 数据权限
+ */
+ private List dataScope;
+
+ /**
+ * 开始时间
+ */
+ private String searchBeginTime;
+
+ /**
+ * 结束时间
+ */
+ private String searchEndTime;
+
+ /**
+ * 状态(字典 0正常 1停用 2删除)
+ */
+ private Integer searchStatus;
+
+ /**
+ * 参数校验分组:分页
+ */
+ public @interface page {
+ }
+
+ /**
+ * 参数校验分组:列表
+ */
+ public @interface list {
+ }
+
+ /**
+ * 参数校验分组:下拉
+ */
+ public @interface dropDown {
+ }
+
+ /**
+ * 参数校验分组:增加
+ */
+ public @interface add {
+ }
+
+ /**
+ * 参数校验分组:编辑
+ */
+ public @interface edit {
+ }
+
+ /**
+ * 参数校验分组:更新信息
+ */
+ public @interface updateInfo {
+ }
+
+ /**
+ * 参数校验分组:修改密码
+ */
+ public @interface updatePwd {
+ }
+
+ /**
+ * 参数校验分组:重置密码
+ */
+ public @interface resetPwd {
+ }
+
+ /**
+ * 参数校验分组:修改头像
+ */
+ public @interface updateAvatar {
+ }
+
+ /**
+ * 参数校验分组:删除
+ */
+ public @interface delete {
+ }
+
+ /**
+ * 参数校验分组:详情
+ */
+ public @interface detail {
+ }
+
+ /**
+ * 参数校验分组:授权角色
+ */
+ public @interface grantRole {
+ }
+
+ /**
+ * 参数校验分组:授权菜单
+ */
+ public @interface grantMenu {
+ }
+
+ /**
+ * 参数校验分组:授权数据
+ */
+ public @interface grantData {
+ }
+
+ /**
+ * 参数校验分组:强退
+ */
+ public @interface force {
+ }
+
+ /**
+ * 参数校验分组:停用
+ */
+ public @interface stop {
+ }
+
+ /**
+ * 参数校验分组:启用
+ */
+ public @interface start {
+ }
+
+ /**
+ * 参数校验分组:部署
+ */
+ public @interface deploy {
+ }
+
+ /**
+ * 参数校验分组:挂起
+ */
+ public @interface suspend {
+ }
+
+ /**
+ * 参数校验分组:激活
+ */
+ public @interface active {
+ }
+
+ /**
+ * 参数校验分组:委托
+ */
+ public @interface entrust {
+ }
+
+ /**
+ * 参数校验分组:转办
+ */
+ public @interface turn {
+ }
+
+ /**
+ * 参数校验分组:追踪
+ */
+ public @interface trace {
+ }
+
+ /**
+ * 参数校验分组:跳转
+ */
+ public @interface jump {
+ }
+
+ /**
+ * 参数校验分组:提交
+ */
+ public @interface submit {
+ }
+
+ /**
+ * 参数校验分组:退回
+ */
+ public @interface back {
+ }
+
+ /**
+ * 参数校验分组:终止
+ */
+ public @interface end {
+ }
+
+ /**
+ * 参数校验分组:导出
+ */
+ public @interface export {
+ }
+
+ /**
+ * 参数校验分组:映射
+ */
+ public @interface mapping {
+ }
+
+ /**
+ * 参数校验分组:切换
+ */
+ public @interface change {
+ }
+
+ /**
+ * 参数校验分组:历史审批记录
+ */
+ public @interface commentHistory {
+ }
+
+ /**
+ * 参数校验分组:修改状态
+ */
+ public @interface changeStatus {
+ }
+
+ /**
+ * 参数校验分组:加签
+ */
+ public @interface addSign {
+ }
+
+ /**
+ * 参数校验分组:减签
+ */
+ public @interface deleteSign {
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/validate/UniqueValidateParam.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/validate/UniqueValidateParam.java
new file mode 100644
index 00000000..c9b01fbc
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/validate/UniqueValidateParam.java
@@ -0,0 +1,56 @@
+package com.cn.xiaonuo.core.pojo.base.validate;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 校验参数时用的方法参数
+ *
+ * @author xuyuxiang
+ * @date 2020/8/17 21:43
+ */
+@Data
+@Builder
+public class UniqueValidateParam {
+
+ /**
+ * 表名称
+ */
+ String tableName;
+
+ /**
+ * 列名称
+ */
+ String columnName;
+
+ /**
+ * 被参数校验时候的字段的值
+ */
+ String value;
+
+ /**
+ * 校验时,是否排除当前的记录
+ */
+ Boolean excludeCurrentRecord;
+
+ /**
+ * 当前记录的主键id
+ */
+ Long id;
+
+ /**
+ * 排除所有被逻辑删除的记录的控制
+ */
+ Boolean excludeLogicDeleteItems;
+
+ /**
+ * 逻辑删除的字段名
+ */
+ String logicDeleteFieldName;
+
+ /**
+ * 逻辑删除的字段的值
+ */
+ String logicDeleteValue;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/wrapper/BaseWrapper.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/wrapper/BaseWrapper.java
new file mode 100644
index 00000000..4cd6e30a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/base/wrapper/BaseWrapper.java
@@ -0,0 +1,47 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.base.wrapper;
+
+import java.util.Map;
+
+/**
+ * 基础包装接口,
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 17:18
+ */
+public interface BaseWrapper {
+
+ /**
+ * 具体包装的过程
+ *
+ * @param beWrappedModel 被包装的原始对象,可以是obj,list,page,PageResult
+ * @return 包装后增加的增量集合
+ * @author xuyuxiang
+ * @date 2020/7/24 17:22
+ */
+ Map doWrap(T beWrappedModel);
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/druid/DruidProperties.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/druid/DruidProperties.java
new file mode 100644
index 00000000..de79e949
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/druid/DruidProperties.java
@@ -0,0 +1,174 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.druid;
+
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.enums.DbIdEnum;
+import com.alibaba.druid.pool.DruidDataSource;
+import lombok.Data;
+
+import java.sql.SQLException;
+import java.util.Properties;
+
+/**
+ * 数据库数据源配置
+ * 说明:类中属性包含默认值的不要在这里修改,应该在"application.yml"中配置
+ *
+ * @author yubaoshan
+ * @date 2017/5/21 11:18
+ */
+@Data
+public class DruidProperties {
+
+ private static final Log log = Log.get();
+
+ /**
+ * oracle校验语句
+ */
+ private final String ORACLE_VALIDATE_QUERY_SQL = "select 1 from dual";
+
+ /**
+ * postgresql校验语句
+ */
+ private final String POSTGRESQL_VALIDATE_QUERY_SQL = "select version()";
+
+ /**
+ * sqlserver校验语句
+ */
+ private final String SQLSERVER_VALIDATE_QUERY_SQL = "select 1";
+
+ /**
+ * mysql校验语句
+ */
+ private final String MYSQL_VALIDATE_QUERY_SQL = "select 1";
+
+ private String url;
+
+ private String username;
+
+ private String password;
+
+ private String driverClassName;
+
+ private Integer initialSize = 2;
+
+ private Integer minIdle = 1;
+
+ private Integer maxActive = 20;
+
+ private Integer maxWait = 60000;
+
+ private Integer timeBetweenEvictionRunsMillis = 60000;
+
+ private Integer minEvictableIdleTimeMillis = 300000;
+
+ private String validationQuery;
+
+ private Boolean testWhileIdle = true;
+
+ private Boolean testOnBorrow = true;
+
+ private Boolean testOnReturn = true;
+
+ private Boolean poolPreparedStatements = true;
+
+ private Integer maxPoolPreparedStatementPerConnectionSize = 20;
+
+ private String filters = "stat,wall";
+
+ private String dataSourceName;
+
+ public void config(DruidDataSource dataSource) {
+
+ dataSource.setUrl(url);
+ dataSource.setUsername(username);
+ dataSource.setPassword(password);
+
+ dataSource.setDriverClassName(driverClassName);
+ //定义初始连接数
+ dataSource.setInitialSize(initialSize);
+ //最小空闲
+ dataSource.setMinIdle(minIdle);
+ //定义最大连接数
+ dataSource.setMaxActive(maxActive);
+ //最长等待时间
+ dataSource.setMaxWait(maxWait);
+
+ //配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+ dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+
+ //配置一个连接在池中最小生存的时间,单位是毫秒
+ dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ dataSource.setValidationQuery(getValidateQueryByUrl(url));
+ dataSource.setTestWhileIdle(testWhileIdle);
+ dataSource.setTestOnBorrow(testOnBorrow);
+ dataSource.setTestOnReturn(testOnReturn);
+
+ //打开PSCache,并且指定每个连接上PSCache的大小
+ dataSource.setPoolPreparedStatements(poolPreparedStatements);
+ dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
+
+ try {
+ dataSource.setFilters(filters);
+ } catch (SQLException e) {
+ log.error(">>> 数据库连接池初始化异常:{}", e.getMessage());
+ }
+ }
+
+ public Properties createProperties() {
+ Properties properties = new Properties();
+ properties.put("url", this.url);
+ properties.put("username", this.username);
+ properties.put("password", this.password);
+ properties.put("driverClassName", this.driverClassName);
+ properties.put("initialSize", this.initialSize);
+ properties.put("maxActive", this.maxActive);
+ properties.put("minIdle", this.minIdle);
+ properties.put("maxWait", this.maxWait);
+ properties.put("poolPreparedStatements", this.poolPreparedStatements);
+ properties.put("maxPoolPreparedStatementPerConnectionSize", this.maxPoolPreparedStatementPerConnectionSize);
+ properties.put("validationQuery", getValidateQueryByUrl(this.url));
+ properties.put("testOnBorrow", this.testOnBorrow);
+ properties.put("testOnReturn", this.testOnReturn);
+ properties.put("testWhileIdle", this.testWhileIdle);
+ properties.put("timeBetweenEvictionRunsMillis", this.timeBetweenEvictionRunsMillis);
+ properties.put("minEvictableIdleTimeMillis", this.minEvictableIdleTimeMillis);
+ properties.put("filters", this.filters);
+ return properties;
+ }
+
+ private String getValidateQueryByUrl(String url) {
+ if (url.contains(DbIdEnum.ORACLE.getName())) {
+ return ORACLE_VALIDATE_QUERY_SQL;
+ } else if (url.contains(DbIdEnum.PG_SQL.getName())) {
+ return POSTGRESQL_VALIDATE_QUERY_SQL;
+ } else if (url.contains(DbIdEnum.MS_SQL.getName())) {
+ return SQLSERVER_VALIDATE_QUERY_SQL;
+ } else {
+ return MYSQL_VALIDATE_QUERY_SQL;
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/email/EmailConfigs.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/email/EmailConfigs.java
new file mode 100644
index 00000000..2edae5cb
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/email/EmailConfigs.java
@@ -0,0 +1,68 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.email;
+
+import lombok.Data;
+
+/**
+ * 邮件的配置
+ *
+ * @author yubaoshan
+ * @date 2020/6/9 23:16
+ */
+@Data
+public class EmailConfigs {
+
+ /**
+ * host
+ */
+ private String host;
+
+ /**
+ * 邮箱用户名
+ */
+ private String user;
+
+ /**
+ * 邮箱密码或者安全码
+ */
+ private String pass;
+
+ /**
+ * 邮箱端口
+ */
+ private Integer port;
+
+ /**
+ * 邮箱发件人
+ */
+ private String from;
+
+ /**
+ * 使用 SSL安全连接
+ */
+ private Boolean sslEnable;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/LoginEmpInfo.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/LoginEmpInfo.java
new file mode 100644
index 00000000..a624fab0
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/LoginEmpInfo.java
@@ -0,0 +1,69 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.login;
+
+import cn.hutool.core.lang.Dict;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 登录用户员工信息
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 16:44
+ */
+@Data
+public class LoginEmpInfo implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 工号
+ */
+ private String jobNum;
+
+ /**
+ * 所属机构id
+ */
+ private Long orgId;
+
+ /**
+ * 所属机构名称
+ */
+ private String orgName;
+
+ /**
+ * 附属机构与职位信息
+ */
+ private List extOrgPos;
+
+ /**
+ * 职位信息
+ */
+ private List positions;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/SysLoginUser.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/SysLoginUser.java
new file mode 100644
index 00000000..b5811e34
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/SysLoginUser.java
@@ -0,0 +1,217 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.login;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.pojo.node.LoginMenuTreeNode;
+import lombok.Data;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 登录用户模型
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 12:21
+ */
+@Data
+public class SysLoginUser implements UserDetails, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ private Long id;
+
+ /**
+ * 账号
+ */
+ private String account;
+
+ /**
+ * 昵称
+ */
+ private String nickName;
+
+ /**
+ * 姓名
+ */
+ private String name;
+
+ /**
+ * 头像
+ */
+ private String avatar;
+
+ /**
+ * 生日
+ */
+ private Date birthday;
+
+ /**
+ * 性别(字典 1男 2女)
+ */
+ private Integer sex;
+
+ /**
+ * 邮箱
+ */
+ private String email;
+
+ /**
+ * 手机
+ */
+ private String phone;
+
+ /**
+ * 电话
+ */
+ private String tel;
+
+ /**
+ * 管理员类型(0超级管理员 1非管理员)
+ */
+ private Integer adminType;
+
+ /**
+ * 最后登陆IP
+ */
+ private String lastLoginIp;
+
+ /**
+ * 最后登陆时间
+ */
+ private String lastLoginTime;
+
+ /**
+ * 最后登陆地址
+ */
+ private String lastLoginAddress;
+
+ /**
+ * 最后登陆所用浏览器
+ */
+ private String lastLoginBrowser;
+
+ /**
+ * 最后登陆所用系统
+ */
+ private String lastLoginOs;
+
+ /**
+ * 员工信息
+ */
+ private LoginEmpInfo loginEmpInfo;
+
+ /**
+ * 具备应用信息
+ */
+ private List apps;
+
+ /**
+ * 角色信息
+ */
+ private List roles;
+
+ /**
+ * 权限信息
+ */
+ private List permissions;
+
+ /**
+ * 登录菜单信息,AntDesign版本菜单
+ */
+ private List menus;
+
+ /**
+ * 数据范围信息
+ */
+ private List dataScopes;
+
+ /**
+ * 租户信息
+ */
+ private Dict tenants;
+
+ /**
+ * 角色名称集合
+ */
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ ArrayList grantedAuthorities = CollectionUtil.newArrayList();
+ if (ObjectUtil.isNotEmpty(roles)) {
+ roles.forEach(dict -> {
+ String roleName = dict.getStr(CommonConstant.NAME);
+ XiaoNuoAuthority xiaoNuoAuthority = new XiaoNuoAuthority(roleName);
+ grantedAuthorities.add(xiaoNuoAuthority);
+ });
+ }
+ return grantedAuthorities;
+ }
+
+ @Override
+ public String getPassword() {
+ return null;
+ }
+
+ @Override
+ public String getUsername() {
+ return this.account;
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ //能生成loginUser就是jwt解析成功,没锁定
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ //能生成loginUser就是jwt解析成功,没锁定
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ //能生成loginUser就是jwt解析成功,没锁定
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ //能生成loginUser就是jwt解析成功,没锁定
+ return true;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/XiaoNuoAuthority.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/XiaoNuoAuthority.java
new file mode 100644
index 00000000..cbe0a6ad
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/login/XiaoNuoAuthority.java
@@ -0,0 +1,48 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.login;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.springframework.security.core.GrantedAuthority;
+
+/**
+ * 用来包装一下角色名称
+ *
+ * @author yubaoshan
+ * @date 2020/4/10 13:08
+ */
+@Data
+@AllArgsConstructor
+public class XiaoNuoAuthority implements GrantedAuthority {
+
+ private String authority;
+
+ @Override
+ public String getAuthority() {
+ return authority;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/AntdBaseTreeNode.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/AntdBaseTreeNode.java
new file mode 100644
index 00000000..0dde57d3
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/AntdBaseTreeNode.java
@@ -0,0 +1,88 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.node;
+
+import com.cn.xiaonuo.core.pojo.base.node.BaseTreeNode;
+import com.cn.xiaonuo.core.pojo.base.node.BaseTreeNode;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * antd通用前端树节点
+ *
+ * @author yubaoshan
+ * @date 2020/6/9 12:42
+ */
+@Data
+public class AntdBaseTreeNode implements BaseTreeNode {
+
+ /**
+ * 主键
+ */
+ private Long id;
+
+ /**
+ * 父id
+ */
+ private Long parentId;
+
+ /**
+ * 名称
+ */
+ private String title;
+
+ /**
+ * 值
+ */
+ private String value;
+
+ /**
+ * 排序,越小优先级越高
+ */
+ private Integer weight;
+
+ /**
+ * 子节点
+ */
+ private List children;
+
+ /**
+ * 父id别名
+ */
+ @Override
+ public Long getPid() {
+ return this.parentId;
+ }
+
+ /**
+ * 子节点
+ */
+ @Override
+ public void setChildren(List children) {
+ this.children = children;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/CommonBaseTreeNode.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/CommonBaseTreeNode.java
new file mode 100644
index 00000000..375c3bb0
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/CommonBaseTreeNode.java
@@ -0,0 +1,91 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.node;
+
+import com.cn.xiaonuo.core.pojo.base.node.BaseTreeNode;
+import com.cn.xiaonuo.core.pojo.base.node.BaseTreeNode;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 通用树节点
+ *
+ * @author xuyuxiang
+ * @date 2020/3/26 14:29
+ */
+@Data
+public class CommonBaseTreeNode implements BaseTreeNode {
+
+ /**
+ * 节点id
+ */
+ private Long id;
+
+ /**
+ * 节点父id
+ */
+ private Long pid;
+
+ /**
+ * 节点名称
+ */
+ private String nodeName;
+
+ /**
+ * 子节点集合
+ */
+ private List children;
+
+ @Override
+ public Long getId() {
+ return this.id;
+ }
+
+ @Override
+ public Long getPid() {
+ return this.pid;
+ }
+
+ @Override
+ public void setChildren(List children) {
+ this.children = children;
+ }
+
+ /*@Override
+ public String getNodeId() {
+ return this.nodeId;
+ }
+
+ @Override
+ public String getNodeParentId() {
+ return this.nodeParentId;
+ }
+
+ @Override
+ public void setChildrenNodes(List childrenNodes) {
+ this.childrenNodes = childrenNodes;
+ }*/
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/LoginMenuTreeNode.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/LoginMenuTreeNode.java
new file mode 100644
index 00000000..2a61fed8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/node/LoginMenuTreeNode.java
@@ -0,0 +1,111 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.node;
+
+import lombok.Data;
+
+/**
+ * 登录菜单
+ *
+ * @author yubaoshan
+ * @date 2020/4/17 17:35
+ */
+@Data
+public class LoginMenuTreeNode {
+
+ /**
+ * id
+ */
+ private Long id;
+
+ /**
+ * 父id
+ */
+ private Long pid;
+
+ /**
+ * 路由名称, 必须设置,且不能重名
+ */
+ private String name;
+
+ /**
+ * 组件
+ */
+ private String component;
+
+ /**
+ * 重定向地址, 访问这个路由时, 自定进行重定向
+ */
+ private String redirect;
+
+ /**
+ * 路由元信息(路由附带扩展信息)
+ */
+ private Meta meta;
+
+ /**
+ * 路径
+ */
+ private String path;
+
+ /**
+ * 控制路由和子路由是否显示在 sidebar
+ */
+ private boolean hidden;
+
+ /**
+ * 路由元信息内部类
+ */
+ @Data
+ public class Meta {
+
+ /**
+ * 路由标题, 用于显示面包屑, 页面标题 *推荐设置
+ */
+ public String title;
+
+ /**
+ * 图标
+ */
+ public String icon;
+
+ /**
+ * 是否可见
+ */
+ public boolean show;
+
+ /**
+ * 如需外部打开,增加:_blank
+ */
+ public String target;
+
+ /**
+ * 内链打开http链接
+ */
+ public String link;
+
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/oauth/OauthConfigs.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/oauth/OauthConfigs.java
new file mode 100644
index 00000000..68f645c5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/oauth/OauthConfigs.java
@@ -0,0 +1,52 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.oauth;
+
+import lombok.Data;
+
+/**
+ * Oauth第三方登录配置
+ *
+ * @author xuyuxiang
+ * @date 2020/7/28 17:18
+ **/
+@Data
+public class OauthConfigs {
+
+ /**
+ * clientId
+ */
+ private String clientId;
+
+ /**
+ * clientSecret
+ */
+ private String clientSecret;
+
+ /**
+ * 回调地址
+ */
+ private String redirectUri;
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/page/PageResult.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/page/PageResult.java
new file mode 100644
index 00000000..5cacecf9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/page/PageResult.java
@@ -0,0 +1,118 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.page;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.PageUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 分页结果集
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:44
+ */
+@Data
+public class PageResult implements Serializable {
+
+ private static final long serialVersionUID = -1L;
+
+ /**
+ * 默认分页彩虹展示数量
+ */
+ public static final int RAINBOW_NUM = 5;
+
+ /**
+ * 第几页
+ */
+ private Integer pageNo = 1;
+
+ /**
+ * 每页条数
+ */
+ private Integer pageSize = 20;
+
+ /**
+ * 总页数
+ */
+ private Integer totalPage = 0;
+
+ /**
+ * 总记录数
+ */
+ private Integer totalRows = 0;
+
+ /**
+ * 结果集
+ */
+ private List rows;
+
+ /**
+ * 分页彩虹
+ */
+ private int[] rainbow;
+
+ public PageResult() {
+ }
+
+ /**
+ * 将mybatis-plus的page转成自定义的PageResult,扩展了totalPage总页数,和rainBow彩虹条
+ *
+ * @author xuyuxiang
+ * @date 2020/4/8 19:20
+ */
+ public PageResult(Page page) {
+ this.setRows(page.getRecords());
+ this.setTotalRows(Convert.toInt(page.getTotal()));
+ this.setPageNo(Convert.toInt(page.getCurrent()));
+ this.setPageSize(Convert.toInt(page.getSize()));
+ this.setTotalPage(PageUtil.totalPage(Convert.toInt(page.getTotal()),
+ Convert.toInt(page.getSize())));
+ this.setRainbow(PageUtil.rainbow(Convert.toInt(page.getCurrent()),
+ Convert.toInt(this.getTotalPage()), RAINBOW_NUM));
+ }
+
+ /**
+ * 将mybatis-plus的page转成自定义的PageResult,扩展了totalPage总页数,和rainBow彩虹条
+ * 可单独设置rows
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 20:55
+ */
+ public PageResult(Page page, List t) {
+ this.setRows(t);
+ this.setTotalRows(Convert.toInt(page.getTotal()));
+ this.setPageNo(Convert.toInt(page.getCurrent()));
+ this.setPageSize(Convert.toInt(page.getSize()));
+ this.setTotalPage(PageUtil.totalPage(Convert.toInt(page.getTotal()),
+ Convert.toInt(page.getSize())));
+ this.setRainbow(PageUtil.rainbow(Convert.toInt(page.getCurrent()),
+ Convert.toInt(this.getTotalPage()), RAINBOW_NUM));
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/ErrorResponseData.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/ErrorResponseData.java
new file mode 100644
index 00000000..6a1f2ad0
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/ErrorResponseData.java
@@ -0,0 +1,56 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.response;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 失败响应结果
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:05
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ErrorResponseData extends ResponseData {
+
+ /**
+ * 异常的具体类名称
+ */
+ private String exceptionClazz;
+
+ ErrorResponseData(String message) {
+ super(false, DEFAULT_ERROR_CODE, message, null);
+ }
+
+ public ErrorResponseData(Integer code, String message) {
+ super(false, code, message, null);
+ }
+
+ ErrorResponseData(Integer code, String message, Object object) {
+ super(false, code, message, object);
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/ResponseData.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/ResponseData.java
new file mode 100644
index 00000000..104d5257
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/ResponseData.java
@@ -0,0 +1,99 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.response;
+
+import lombok.Data;
+
+/**
+ * 响应结果数据
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:04
+ */
+@Data
+public class ResponseData {
+
+ public static final String DEFAULT_SUCCESS_MESSAGE = "请求成功";
+
+ public static final String DEFAULT_ERROR_MESSAGE = "网络异常";
+
+ public static final Integer DEFAULT_SUCCESS_CODE = 200;
+
+ public static final Integer DEFAULT_ERROR_CODE = 500;
+
+ /**
+ * 请求是否成功
+ */
+ private Boolean success;
+
+ /**
+ * 响应状态码
+ */
+ private Integer code;
+
+ /**
+ * 响应信息
+ */
+ private String message;
+
+ /**
+ * 响应对象
+ */
+ private Object data;
+
+ public ResponseData() {
+ }
+
+ public ResponseData(Boolean success, Integer code, String message, Object data) {
+ this.success = success;
+ this.code = code;
+ this.message = message;
+ this.data = data;
+ }
+
+ public static SuccessResponseData success() {
+ return new SuccessResponseData();
+ }
+
+ public static SuccessResponseData success(Object object) {
+ return new SuccessResponseData(object);
+ }
+
+ public static SuccessResponseData success(Integer code, String message, Object object) {
+ return new SuccessResponseData(code, message, object);
+ }
+
+ public static ErrorResponseData error(String message) {
+ return new ErrorResponseData(message);
+ }
+
+ public static ErrorResponseData error(Integer code, String message) {
+ return new ErrorResponseData(code, message);
+ }
+
+ public static ErrorResponseData error(Integer code, String message, Object object) {
+ return new ErrorResponseData(code, message, object);
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/SuccessResponseData.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/SuccessResponseData.java
new file mode 100644
index 00000000..74e74a18
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/response/SuccessResponseData.java
@@ -0,0 +1,46 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.response;
+
+/**
+ * 成功响应结果
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:04
+ */
+public class SuccessResponseData extends ResponseData {
+
+ public SuccessResponseData() {
+ super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, null);
+ }
+
+ public SuccessResponseData(Object object) {
+ super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, object);
+ }
+
+ public SuccessResponseData(Integer code, String message, Object object) {
+ super(true, code, message, object);
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/sms/AliyunSmsConfigs.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/sms/AliyunSmsConfigs.java
new file mode 100644
index 00000000..03f4744f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/sms/AliyunSmsConfigs.java
@@ -0,0 +1,63 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.sms;
+
+import lombok.Data;
+
+/**
+ * 阿里云oss相关配置
+ *
+ * @author yubaoshan
+ * @date 2018/6/27 13:20
+ */
+@Data
+public class AliyunSmsConfigs {
+
+ /**
+ * accessKeyId
+ */
+ private String accessKeyId;
+
+ /**
+ * accessKeySecret
+ */
+ private String accessKeySecret;
+
+ /**
+ * 签名名称
+ */
+ private String signName;
+
+ /**
+ * 登录验证码的模板
+ */
+ private String loginTemplateCode;
+
+ /**
+ * 短信失效时间(分钟)
+ */
+ private Integer invalidateMinutes = 2;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/sms/TencentSmsConfigs.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/sms/TencentSmsConfigs.java
new file mode 100644
index 00000000..56ce93f2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/pojo/sms/TencentSmsConfigs.java
@@ -0,0 +1,64 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.pojo.sms;
+
+import lombok.Data;
+
+/**
+ * 阿里云oss相关配置
+ *
+ * @author yubaoshan
+ * @date 2018/6/27 13:20
+ */
+@Data
+public class TencentSmsConfigs {
+
+ /**
+ * secretId
+ */
+ private String secretId;
+
+ /**
+ * secretKey
+ */
+ private String secretKey;
+
+ /**
+ * 应用控制台应用管理中的应用id
+ *
+ * 在 [短信控制台] 添加应用后生成的实际 SDKAppID,例如1400006666
+ *
+ * 短信控制台:https://console.cloud.tencent.com/smsv2
+ */
+ private String sdkAppId;
+
+ /**
+ * 签名,一般为中文名
+ *
+ * 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,可登录 [短信控制台] 查看签名信息
+ */
+ private String sign;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/SmsSender.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/SmsSender.java
new file mode 100644
index 00000000..1de7ac42
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/SmsSender.java
@@ -0,0 +1,26 @@
+package com.cn.xiaonuo.core.sms;
+
+import java.util.Map;
+
+/**
+ * 短信发送服务
+ *
+ * @author xuyuxiang
+ * @date 2018-07-06-下午2:14
+ */
+public interface SmsSender {
+
+ /**
+ * 发送短信
+ *
+ * 如果是腾讯云,params要用LinkedHashMap,保证顺序
+ *
+ * @param phone 电话号码
+ * @param templateCode 模板号码
+ * @param params 模板里参数的集合
+ * @author xuyuxiang
+ * @date 2018/7/6 下午2:32
+ */
+ void sendSms(String phone, String templateCode, Map params);
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/AliyunSmsSender.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/AliyunSmsSender.java
new file mode 100644
index 00000000..6219f26b
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/AliyunSmsSender.java
@@ -0,0 +1,156 @@
+package com.cn.xiaonuo.core.sms.modular.aliyun;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyuncs.CommonRequest;
+import com.aliyuncs.CommonResponse;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.profile.DefaultProfile;
+import com.cn.xiaonuo.core.sms.SmsSender;
+import com.cn.xiaonuo.core.sms.modular.aliyun.enums.AliyunSmsResultEnum;
+import com.cn.xiaonuo.core.sms.modular.aliyun.exp.AliyunSmsException;
+import com.cn.xiaonuo.core.sms.modular.aliyun.msign.MultiSignManager;
+import com.cn.xiaonuo.core.sms.modular.aliyun.prop.AliyunSmsProperties;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Map;
+
+/**
+ * 阿里云短信发送服务
+ *
+ * @author xuyuxiang
+ * @date 2018-07-06-下午2:15
+ */
+@Slf4j
+public class AliyunSmsSender implements SmsSender {
+
+ private final MultiSignManager multiSignManager;
+
+ private final AliyunSmsProperties aliyunSmsProperties;
+
+ public AliyunSmsSender(MultiSignManager multiSignManager, AliyunSmsProperties aliyunSmsProperties) {
+ this.multiSignManager = multiSignManager;
+ this.aliyunSmsProperties = aliyunSmsProperties;
+ }
+
+ @Override
+ public void sendSms(String phone, String templateCode, Map params) {
+
+ log.info("开始发送阿里云短信,手机号是:" + phone + ",模板号是:" + templateCode + ",参数是:" + params);
+
+ // 检验参数是否合法
+ assertSendSmsParams(phone, templateCode, params, aliyunSmsProperties);
+
+ // 初始化client profile
+ IAcsClient iAcsClient = initClient();
+
+ // 组装请求对象
+ JSONObject smsRes = createSmsRequest(phone, templateCode, params, iAcsClient);
+
+ // 如果返回ok则发送成功
+ if (!AliyunSmsResultEnum.OK.getCode().equals(smsRes.getString("Code"))) {
+
+ // 返回其他状态码根据情况抛出业务异常
+ String code = AliyunSmsResultEnum.SYSTEM_ERROR.getCode();
+ String errorMessage = AliyunSmsResultEnum.SYSTEM_ERROR.getMessage();
+ for (AliyunSmsResultEnum smsExceptionEnum : AliyunSmsResultEnum.values()) {
+ if (smsExceptionEnum.getCode().equals(smsRes.getString("Code"))) {
+ code = smsExceptionEnum.getCode();
+ errorMessage = smsExceptionEnum.getMessage();
+ }
+ }
+ log.error("发送短信异常!code = " + code + ",message = " + errorMessage);
+ throw new AliyunSmsException(code, errorMessage);
+ }
+ }
+
+ /**
+ * 初始化短信发送的客户端
+ *
+ * @author xuyuxiang
+ * @date 2018/7/6 下午3:57
+ */
+ private IAcsClient initClient() {
+ final String accessKeyId = aliyunSmsProperties.getAccessKeyId();
+ final String accessKeySecret = aliyunSmsProperties.getAccessKeySecret();
+
+ // 创建DefaultAcsClient实例并初始化
+ DefaultProfile profile = DefaultProfile.getProfile(aliyunSmsProperties.getRegionId(), accessKeyId, accessKeySecret);
+ return new DefaultAcsClient(profile);
+ }
+
+ /**
+ * 组装请求对象
+ *
+ * @author xuyuxiang
+ * @date 2018/7/6 下午3:00
+ */
+ private JSONObject createSmsRequest(String phoneNumber, String templateCode, Map params, IAcsClient acsClient) {
+ CommonRequest request = new CommonRequest();
+ request.setSysDomain(aliyunSmsProperties.getSmsDomain());
+ request.setSysVersion(aliyunSmsProperties.getSmsVersion());
+ request.setSysAction(aliyunSmsProperties.getSmsSendAction());
+
+ // 接收短信的手机号码
+ request.putQueryParameter("PhoneNumbers", phoneNumber);
+
+ // 短信签名名称。请在控制台签名管理页面签名名称一列查看(必须是已添加、并通过审核的短信签名)。
+ request.putQueryParameter("SignName", this.getSmsSign(phoneNumber));
+
+ // 短信模板ID
+ request.putQueryParameter("TemplateCode", templateCode);
+
+ // 短信模板变量对应的实际值,JSON格式。
+ request.putQueryParameter("TemplateParam", JSON.toJSONString(params));
+
+ //请求失败这里会抛ClientException异常
+ CommonResponse commonResponse;
+ try {
+ commonResponse = acsClient.getCommonResponse(request);
+ String data = commonResponse.getData();
+ String jsonResult = data.replaceAll("'\'", "");
+ log.info("获取到发送短信的响应结果!{}", jsonResult);
+ return JSON.parseObject(jsonResult);
+ } catch (ClientException e) {
+ log.error("初始化阿里云sms异常!可能是accessKey和secret错误!", e);
+ throw new AliyunSmsException(AliyunSmsResultEnum.INIT_SMS_CLIENT_ERROR.getCode(),
+ AliyunSmsResultEnum.INIT_SMS_CLIENT_ERROR.getMessage());
+ }
+ }
+
+ /**
+ * 校验发送短信的参数是否正确
+ *
+ * @author xuyuxiang
+ * @date 2018/7/6 下午3:19
+ */
+ private void assertSendSmsParams(String phoneNumber, String templateCode, Map params,
+ AliyunSmsProperties aliyunSmsProperties) {
+ if (ObjectUtil.hasEmpty(phoneNumber, templateCode, params, aliyunSmsProperties)) {
+ log.error("阿里云短信发送异常!请求参数存在空!");
+ throw new AliyunSmsException(AliyunSmsResultEnum.PARAM_NULL.getCode(), AliyunSmsResultEnum.PARAM_NULL.getMessage());
+ }
+ }
+
+ /**
+ * 获取sms发送的sign标识,参数phone是发送的手机号码
+ *
+ * @author xuyuxiang
+ * @date 2018/8/13 21:23
+ */
+ private String getSmsSign(String phone) {
+ String signName = aliyunSmsProperties.getSignName();
+
+ // 如果是单个签名就用一个签名发
+ if (!signName.contains(",")) {
+ log.info("发送短信,签名为:" + signName + ",电话为:" + phone);
+ return signName;
+ } else {
+ return multiSignManager.getSign(phone, signName);
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/enums/AliyunSmsResultEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/enums/AliyunSmsResultEnum.java
new file mode 100644
index 00000000..341d87c1
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/enums/AliyunSmsResultEnum.java
@@ -0,0 +1,124 @@
+package com.cn.xiaonuo.core.sms.modular.aliyun.enums;
+
+
+import lombok.Getter;
+
+/**
+ * 短信发送异常相关枚举
+ *
+ * @author xuyuxiang
+ * @date 2018/1/4 22:40
+ */
+@Getter
+public enum AliyunSmsResultEnum {
+
+
+ /**
+ * 初始化sms客户端错误,accessKey错误
+ */
+ INIT_SMS_CLIENT_ERROR("SMS_CLIENT_INIT_ERROR", "初始化sms客户端错误,accessKey错误"),
+
+ /**
+ * 请求参数为空
+ */
+ PARAM_NULL("NULL", "请求参数为空"),
+
+ /**
+ * 请求成功
+ */
+ OK("OK", "请求成功"),
+
+ /**
+ * RAM权限DENY
+ */
+ RAM_PERMISSION_DENY("isp.RAM_PERMISSION_DENY", "RAM权限DENY"),
+
+ /**
+ * 产品未开通
+ */
+ PRODUCT_UNSUBSCRIBE("isv.PRODUCT_UNSUBSCRIBE", "产品未开通"),
+
+ /**
+ * 账户不存在
+ */
+ ACCOUNT_NOT_EXISTS("isv.ACCOUNT_NOT_EXISTS", "账户不存在"),
+
+ /**
+ * 账户异常
+ */
+ ACCOUNT_ABNORMAL("isv.ACCOUNT_ABNORMAL", "账户异常"),
+
+ /**
+ * 短信模板不合法
+ */
+ SMS_TEMPLATE_ILLEGAL("isv.SMS_TEMPLATE_ILLEGAL", "短信模板不合法"),
+
+ /**
+ * 短信签名不合法
+ */
+ SMS_SIGNATURE_ILLEGAL("isv.SMS_SIGNATURE_ILLEGAL", "短信签名不合法"),
+
+ /**
+ * 参数异常
+ */
+ INVALID_PARAMETERS("isv.INVALID_PARAMETERS", "参数异常"),
+
+ /**
+ * 系统错误
+ */
+ SYSTEM_ERROR("isp.SYSTEM_ERROR", "系统错误"),
+
+ /**
+ * 非法手机号
+ */
+ MOBILE_NUMBER_ILLEGAL("isv.MOBILE_NUMBER_ILLEGAL", "非法手机号"),
+
+ /**
+ * 手机号码数量超过限制
+ */
+ MOBILE_COUNT_OVER_LIMIT("isv.MOBILE_COUNT_OVER_LIMIT", "手机号码数量超过限制"),
+
+ /**
+ * 模板缺少变量
+ */
+ TEMPLATE_MISSING_PARAMETERS("isv.TEMPLATE_MISSING_PARAMETERS", "模板缺少变量"),
+
+ /**
+ * 发送短信过于频繁,请稍后再试
+ */
+ BUSINESS_LIMIT_CONTROL("isv.BUSINESS_LIMIT_CONTROL", "发送短信过于频繁,请稍后再试"),
+
+ /**
+ * JSON参数不合法,只接受字符串值
+ */
+ INVALID_JSON_PARAM("isv.INVALID_JSON_PARAM", "JSON参数不合法,只接受字符串值"),
+
+ /**
+ * 黑名单管控
+ */
+ BLACK_KEY_CONTROL_LIMIT("isv.BLACK_KEY_CONTROL_LIMIT", "黑名单管控"),
+
+ /**
+ * 参数超出长度限制
+ */
+ PARAM_LENGTH_LIMIT("isv.PARAM_LENGTH_LIMIT", "参数超出长度限制"),
+
+ /**
+ * 不支持URL
+ */
+ PARAM_NOT_SUPPORT_URL("isv.PARAM_NOT_SUPPORT_URL", "不支持URL"),
+
+ /**
+ * 账户余额不足
+ */
+ AMOUNT_NOT_ENOUGH("isv.AMOUNT_NOT_ENOUGH", "账户余额不足");
+
+ private String code;
+
+ private final String message;
+
+ AliyunSmsResultEnum(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/exp/AliyunSmsException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/exp/AliyunSmsException.java
new file mode 100644
index 00000000..e1b4fc03
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/exp/AliyunSmsException.java
@@ -0,0 +1,23 @@
+package com.cn.xiaonuo.core.sms.modular.aliyun.exp;
+
+import lombok.Getter;
+
+/**
+ * 短信发送异常
+ *
+ * @author xuyuxiang
+ * @date 2018-07-06-下午3:00
+ */
+@Getter
+public class AliyunSmsException extends RuntimeException {
+
+ private final String code;
+
+ private final String errorMessage;
+
+ public AliyunSmsException(String code, String errorMessage) {
+ super(errorMessage);
+ this.code = code;
+ this.errorMessage = errorMessage;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/msign/MultiSignManager.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/msign/MultiSignManager.java
new file mode 100644
index 00000000..40cb1723
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/msign/MultiSignManager.java
@@ -0,0 +1,22 @@
+package com.cn.xiaonuo.core.sms.modular.aliyun.msign;
+
+/**
+ * 多个签名的缓存管理,为了打破一个签名发送次数的限制
+ *
+ * @author xuyuxiang
+ * @date 2018-09-21-上午10:47
+ */
+public interface MultiSignManager {
+
+ /**
+ * 获取签名
+ *
+ * @param phone 电话
+ * @param signName 发送短信用的签名,是一个以逗号隔开的字符串
+ * @return 签名
+ * @author xuyuxiang
+ * @date 2018/9/21 上午10:51
+ */
+ String getSign(String phone, String signName);
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/msign/impl/MapBasedMultiSignManager.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/msign/impl/MapBasedMultiSignManager.java
new file mode 100644
index 00000000..c333a301
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/msign/impl/MapBasedMultiSignManager.java
@@ -0,0 +1,64 @@
+package com.cn.xiaonuo.core.sms.modular.aliyun.msign.impl;
+
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.sms.modular.aliyun.msign.MultiSignManager;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 获取缓存的map中的签名
+ *
+ * @author xuyuxiang
+ * @date 2018-09-21-上午10:49
+ */
+public class MapBasedMultiSignManager implements MultiSignManager {
+
+ private static final Log log = Log.get();
+
+ private static final int CLEAR_COUNT = 1000;
+
+ private final Map cacheMap = new ConcurrentHashMap<>();
+
+ @Override
+ public String getSign(String phone, String signName) {
+
+ //先清除map
+ clearMap();
+
+ //分割签名数组
+ String[] signNames = signName.split(",");
+
+ //获取上次发送的时候用的哪个签名,这次换一个
+ Object lastSignName = cacheMap.get(phone);
+ if (lastSignName == null) {
+ cacheMap.put(phone, signNames[0]);
+ log.info("发送短信,签名为:" + signNames[0] + ",电话为:" + phone);
+ return signNames[0];
+ } else {
+ for (String name : signNames) {
+ if (!name.equals(lastSignName)) {
+ cacheMap.put(phone, name);
+ log.info("发送短信,签名为:" + name + ",电话为:" + phone);
+ return name;
+ }
+ }
+ cacheMap.put(phone, signNames[0]);
+ log.info("发送短信,签名为:" + signNames[0] + ",电话为:" + phone);
+ return signNames[0];
+ }
+ }
+
+ /**
+ * 每隔一段时间清除下map
+ *
+ * @author xuyuxiang
+ * @date 2018/9/21 上午10:57
+ */
+ private void clearMap() {
+ if (cacheMap.size() >= CLEAR_COUNT) {
+ cacheMap.clear();
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/prop/AliyunSmsProperties.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/prop/AliyunSmsProperties.java
new file mode 100644
index 00000000..b6f20798
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/aliyun/prop/AliyunSmsProperties.java
@@ -0,0 +1,54 @@
+package com.cn.xiaonuo.core.sms.modular.aliyun.prop;
+
+import lombok.Data;
+
+/**
+ * 阿里云oss相关配置
+ *
+ * @author xuyuxiang
+ * @date 2018-06-27-下午1:20
+ */
+@Data
+public class AliyunSmsProperties {
+
+ /**
+ * accessKeyId
+ */
+ private String accessKeyId;
+
+ /**
+ * accessKeySecret
+ */
+ private String accessKeySecret;
+
+ /**
+ * 签名名称
+ */
+ private String signName;
+
+ /**
+ * 短信失效时间(分钟)
+ */
+ private Integer invalidateMinutes = 2;
+
+ /**
+ * 地域id(阿里云sdk默认的,一般不用修改)
+ */
+ private String regionId = "cn-hangzhou";
+
+ /**
+ * domain(阿里云sdk默认的,一般不用修改)
+ */
+ private String smsDomain = "dysmsapi.aliyuncs.com";
+
+ /**
+ * version(阿里云sdk默认的,一般不用修改)
+ */
+ private String smsVersion = "2017-05-25";
+
+ /**
+ * sms发送(阿里云sdk默认的,一般不用修改)
+ */
+ private String smsSendAction = "SendSms";
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/TencentSmsSender.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/TencentSmsSender.java
new file mode 100644
index 00000000..37a7ab48
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/TencentSmsSender.java
@@ -0,0 +1,89 @@
+package com.cn.xiaonuo.core.sms.modular.tencent;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.cn.xiaonuo.core.sms.SmsSender;
+import com.cn.xiaonuo.core.sms.modular.tencent.exp.TencentSmsException;
+import com.cn.xiaonuo.core.sms.modular.tencent.prop.TencentSmsProperties;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.sms.v20190711.SmsClient;
+import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
+import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
+import com.tencentcloudapi.sms.v20190711.models.SendStatus;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * 腾讯云短信发送
+ *
+ * @author xuyuxiang
+ * @date 2020/5/24 17:58
+ */
+public class TencentSmsSender implements SmsSender {
+
+ private TencentSmsProperties tencentSmsProperties;
+
+ public TencentSmsSender(TencentSmsProperties tencentSmsProperties) {
+ this.tencentSmsProperties = tencentSmsProperties;
+ }
+
+ @Override
+ public void sendSms(String phone, String templateCode, Map params) {
+ try {
+
+ // 实例化一个认证对象
+ Credential cred = new Credential(
+ tencentSmsProperties.getSecretId(), tencentSmsProperties.getSecretKey());
+
+ // 实例化一个 http 选项,可选,无特殊需求时可以跳过
+ HttpProfile httpProfile = new HttpProfile();
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setSignMethod("HmacSHA256");
+ clientProfile.setHttpProfile(httpProfile);
+
+ // 实例化 SMS 的 client 对象
+ SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile);
+
+ // 构建请求参数
+ SendSmsRequest req = new SendSmsRequest();
+
+ // 设置应用id
+ req.setSmsSdkAppid(tencentSmsProperties.getSdkAppId());
+
+ // 设置签名
+ req.setSign(tencentSmsProperties.getSign());
+
+ // 设置模板id
+ req.setTemplateID(templateCode);
+
+ // 默认发送一个手机短信
+ String[] phoneNumbers = {"+86" + phone};
+ req.setPhoneNumberSet(phoneNumbers);
+
+ // 模板参数
+ if (params != null && params.size() > 0) {
+ LinkedList strings = new LinkedList<>();
+ Collection values = params.values();
+ for (Object value : values) {
+ strings.add(value.toString());
+ }
+ req.setTemplateParamSet(ArrayUtil.toArray(strings, String.class));
+ }
+
+ SendSmsResponse res = client.SendSms(req);
+
+ SendStatus[] sendStatusSet = res.getSendStatusSet();
+ if (sendStatusSet != null && sendStatusSet.length > 0) {
+ if (!sendStatusSet[0].getCode().equals("Ok")) {
+ throw new TencentSmsException(sendStatusSet[0].getCode(), sendStatusSet[0].getMessage());
+ }
+ }
+ } catch (TencentCloudSDKException e) {
+ throw new TencentSmsException("500", e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/exp/TencentSmsException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/exp/TencentSmsException.java
new file mode 100644
index 00000000..21fa29ec
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/exp/TencentSmsException.java
@@ -0,0 +1,23 @@
+package com.cn.xiaonuo.core.sms.modular.tencent.exp;
+
+import lombok.Getter;
+
+/**
+ * 短信发送异常
+ *
+ * @author xuyuxiang
+ * @date 2018-07-06-下午3:00
+ */
+@Getter
+public class TencentSmsException extends RuntimeException {
+
+ private final String code;
+
+ private final String errorMessage;
+
+ public TencentSmsException(String code, String errorMessage) {
+ super(errorMessage);
+ this.code = code;
+ this.errorMessage = errorMessage;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/prop/TencentSmsProperties.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/prop/TencentSmsProperties.java
new file mode 100644
index 00000000..43967455
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/sms/modular/tencent/prop/TencentSmsProperties.java
@@ -0,0 +1,40 @@
+package com.cn.xiaonuo.core.sms.modular.tencent.prop;
+
+import lombok.Data;
+
+/**
+ * 腾讯云短信配置
+ *
+ * @author xuyuxiang
+ * @date 2020/5/24 18:01
+ */
+@Data
+public class TencentSmsProperties {
+
+ /**
+ * secretId
+ */
+ private String secretId;
+
+ /**
+ * secretKey
+ */
+ private String secretKey;
+
+ /**
+ * 应用控制台应用管理中的应用id
+ *
+ * 在 [短信控制台] 添加应用后生成的实际 SDKAppID,例如1400006666
+ *
+ * 短信控制台:https://console.cloud.tencent.com/smsv2
+ */
+ private String sdkAppId;
+
+ /**
+ * 签名,一般为中文名
+ *
+ * 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,可登录 [短信控制台] 查看签名信息
+ */
+ private String sign;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/consts/TenantConstants.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/consts/TenantConstants.java
new file mode 100644
index 00000000..01b768ae
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/consts/TenantConstants.java
@@ -0,0 +1,31 @@
+package com.cn.xiaonuo.core.tenant.consts;
+
+/**
+ * 租户的常量
+ *
+ * @author xuyuxiang
+ * @date 2019-06-18-16:24
+ */
+public interface TenantConstants {
+
+ /**
+ * 租户数据源标识前缀
+ */
+ String TENANT_DB_PREFIX = "xiaonuo_tenant_db_";
+
+ /**
+ * 初始化租户的sql文件名称
+ */
+ String INIT_SQL_FILE_NAME = "tenant_init.sql";
+
+ /**
+ * 租户编码的字段名称
+ */
+ String TENANT_CODE = "tenantCode";
+
+ /**
+ * 租户对应的数据库编码字段名称
+ */
+ String TENANT_DB_NAME = "tenantDbName";
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/consts/TenantExpEnumConstant.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/consts/TenantExpEnumConstant.java
new file mode 100644
index 00000000..e235e1a6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/consts/TenantExpEnumConstant.java
@@ -0,0 +1,21 @@
+package com.cn.xiaonuo.core.tenant.consts;
+
+/**
+ * 多租户的异常编码规范
+ *
+ * @author xuyuxiang
+ * @date 2020/9/3
+ */
+public interface TenantExpEnumConstant {
+
+ /**
+ * 模块分类编码(2位)
+ */
+ int TENANT_MODULE_EXP_CODE = 60;
+
+ /**
+ * 租户操作相关分类编码(4位)
+ */
+ int TENANT_EXCEPTION_ENUM = 1100;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/context/TenantCodeHolder.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/context/TenantCodeHolder.java
new file mode 100644
index 00000000..0133164a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/context/TenantCodeHolder.java
@@ -0,0 +1,24 @@
+package com.cn.xiaonuo.core.tenant.context;
+
+/**
+ * 租户编码的临时存放
+ *
+ * @author xuyuxiang
+ * @date 2019-06-19-14:08
+ */
+public class TenantCodeHolder {
+
+ private static final ThreadLocal TENANT_CODE_HOLDER = new ThreadLocal<>();
+
+ public static void put(String value) {
+ TENANT_CODE_HOLDER.set(value);
+ }
+
+ public static String get() {
+ return TENANT_CODE_HOLDER.get();
+ }
+
+ public static void remove() {
+ TENANT_CODE_HOLDER.remove();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/context/TenantDbNameHolder.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/context/TenantDbNameHolder.java
new file mode 100644
index 00000000..e0b20338
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/context/TenantDbNameHolder.java
@@ -0,0 +1,24 @@
+package com.cn.xiaonuo.core.tenant.context;
+
+/**
+ * 租户对应的数据库的临时存放
+ *
+ * @author xuyuxiang
+ * @date 2019-06-19-14:08
+ */
+public class TenantDbNameHolder {
+
+ private static final ThreadLocal DB_NAME_HOLDER = new ThreadLocal<>();
+
+ public static void put(String value) {
+ DB_NAME_HOLDER.set(value);
+ }
+
+ public static String get() {
+ return DB_NAME_HOLDER.get();
+ }
+
+ public static void remove() {
+ DB_NAME_HOLDER.remove();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/entity/TenantInfo.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/entity/TenantInfo.java
new file mode 100644
index 00000000..51c05c7e
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/entity/TenantInfo.java
@@ -0,0 +1,71 @@
+package com.cn.xiaonuo.core.tenant.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * 租户表
+ *
+ *
+ * @author yubaoshan
+ * @since 2019-06-16
+ */
+@TableName("sys_tenant_info")
+@Data
+public class TenantInfo implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键id
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 租户名称
+ */
+ @TableField("name")
+ private String name;
+
+ /**
+ * 租户的编码
+ */
+ @TableField("code")
+ private String code;
+
+ /**
+ * 关联的数据库名称
+ */
+ @TableField("db_name")
+ private String dbName;
+
+ /**
+ * 创建时间
+ */
+ @TableField(value = "create_time", fill = FieldFill.INSERT)
+ private Date createTime;
+
+ /**
+ * 创建人
+ */
+ @TableField(value = "create_user", fill = FieldFill.INSERT)
+ private Long createUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField(value = "update_time", fill = FieldFill.UPDATE)
+ private Date updateTime;
+
+ /**
+ * 更新人
+ */
+ @TableField(value = "update_user", fill = FieldFill.UPDATE)
+ private Long updateUser;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/exception/TenantException.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/exception/TenantException.java
new file mode 100644
index 00000000..41762725
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/exception/TenantException.java
@@ -0,0 +1,18 @@
+package com.cn.xiaonuo.core.tenant.exception;
+
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+
+/**
+ * 多租户的异常
+ *
+ * @author xuyuxiang
+ * @date 2020/9/3
+ */
+public class TenantException extends ServiceException {
+
+ public TenantException(AbstractBaseExceptionEnum exception) {
+ super(exception);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/exception/enums/TenantExceptionEnum.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/exception/enums/TenantExceptionEnum.java
new file mode 100644
index 00000000..879bc787
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/exception/enums/TenantExceptionEnum.java
@@ -0,0 +1,56 @@
+package com.cn.xiaonuo.core.tenant.exception.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.core.tenant.consts.TenantExpEnumConstant;
+
+/**
+ * 多租户异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/8/24
+ */
+@ExpEnumType(module = TenantExpEnumConstant.TENANT_MODULE_EXP_CODE, kind = TenantExpEnumConstant.TENANT_EXCEPTION_ENUM)
+public enum TenantExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 更新租户的密码错误
+ */
+ UPDATE_TENANT_PASSWORD_ERROR(1, "更新租户的密码错误"),
+
+ /**
+ * 多数据源模块未启用,找不到DatabaseInfoService
+ */
+ DBS_MODULAR_NOT_ENABLE_ERROR(2, "多数据源模块未启用,找不到DatabaseInfoService"),
+
+ /**
+ * 找不到该租户信息
+ */
+ CNAT_FIND_TENANT_ERROR(3, "找不到该租户信息"),
+
+ /**
+ * 多租户模块未启用,找不到TenantInfoService
+ */
+ TENANT_MODULE_NOT_ENABLE_ERROR(4, "多租户模块未启用,找不到TenantInfoService");
+
+ TenantExceptionEnum(int code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ private final Integer code;
+
+ private final String message;
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/params/TenantInfoParam.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/params/TenantInfoParam.java
new file mode 100644
index 00000000..6bf50041
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/params/TenantInfoParam.java
@@ -0,0 +1,54 @@
+package com.cn.xiaonuo.core.tenant.params;
+
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ *
+ * 租户表
+ *
+ *
+ * @author yubaoshan
+ * @since 2019-06-16
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class TenantInfoParam extends BaseParam {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键id
+ */
+ @NotNull(message = "id不能为空,请检查id参数", groups = {edit.class, delete.class, detail.class})
+ private Long id;
+
+ /**
+ * 租户名称
+ */
+ @NotBlank(message = "租户名称不能为空,请检查name参数", groups = {add.class, edit.class})
+ private String name;
+
+ /**
+ * 租户的编码
+ */
+ @NotBlank(message = "租户的编码不能为空,请检查code参数", groups = {add.class, edit.class})
+ private String code;
+
+ /**
+ * 租户管理员账号
+ */
+ @NotBlank(message = "租户管理员账号不能为空,请检查adminUsername参数", groups = {add.class})
+ private String adminUsername;
+
+ /**
+ * 租户管理员密码
+ */
+ @NotBlank(message = "租户管理员账号不能为空,请检查adminPassword参数", groups = {add.class})
+ private String adminPassword;
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/service/TenantInfoService.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/service/TenantInfoService.java
new file mode 100644
index 00000000..98a9e023
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/tenant/service/TenantInfoService.java
@@ -0,0 +1,63 @@
+package com.cn.xiaonuo.core.tenant.service;
+
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.core.tenant.entity.TenantInfo;
+import com.cn.xiaonuo.core.tenant.params.TenantInfoParam;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * 租户表 服务类
+ *
+ * @author yubaoshan
+ * @since 2019-06-16
+ */
+public interface TenantInfoService extends IService {
+
+ /**
+ * 新增租户
+ *
+ * @param param 添加参数
+ * @author yubaoshan
+ * @date 2019-06-16
+ */
+ void add(TenantInfoParam param);
+
+ /**
+ * 删除租户
+ *
+ * @param param 删除参数
+ * @author yubaoshan
+ * @date 2019-06-16
+ */
+ void delete(TenantInfoParam param);
+
+ /**
+ * 更新租户
+ *
+ * @param param 更新参数
+ * @author yubaoshan
+ * @date 2019-06-16
+ */
+ void update(TenantInfoParam param);
+
+ /**
+ * 分页查询租户列表
+ *
+ * @param param 查询参数
+ * @return 查询结果
+ * @author xuyuxiang
+ * @date 2020/9/3
+ */
+ PageResult page(TenantInfoParam param);
+
+ /**
+ * 获取租户信息,通过租户编码
+ *
+ * @param code 租户编码
+ * @return 租户信息
+ * @author xuyuxiang
+ * @date 2019-06-19 14:17
+ */
+ TenantInfo getByCode(String code);
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/timer/TimerTaskRunner.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/timer/TimerTaskRunner.java
new file mode 100644
index 00000000..3beacd80
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/timer/TimerTaskRunner.java
@@ -0,0 +1,45 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.timer;
+
+/**
+ * 定时器执行者
+ *
+ * 定时器都要实现本接口,并需要把实现类加入到spring容器中
+ *
+ * @author yubaoshan
+ * @date 2020/6/28 21:28
+ */
+public interface TimerTaskRunner {
+
+ /**
+ * 任务执行的具体内容
+ *
+ * @author yubaoshan
+ * @date 2020/6/28 21:29
+ */
+ void action();
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/AopTargetUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/AopTargetUtil.java
new file mode 100644
index 00000000..d5d443b5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/AopTargetUtil.java
@@ -0,0 +1,88 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.context.requestno.RequestNoContext;
+import org.springframework.aop.framework.AdvisedSupport;
+import org.springframework.aop.framework.AopProxy;
+import org.springframework.aop.support.AopUtils;
+
+import java.lang.reflect.Field;
+
+/**
+ * 获取代理原始对象的工具
+ *
+ * @author yubaoshan
+ * @date 2018/2/21 17:09
+ */
+public class AopTargetUtil {
+
+ private static final Log log = Log.get();
+
+ /**
+ * 获取被代理的对象本身
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:02
+ */
+ public static Object getTarget(Object proxy) {
+
+ // 判断是不是代理对象,如果不是直接返回
+ if (!AopUtils.isAopProxy(proxy)) {
+ return proxy;
+ }
+
+ try {
+ if (AopUtils.isJdkDynamicProxy(proxy)) {
+ return getJdkDynamicProxyTargetObject(proxy);
+ } else {
+ return getCglibProxyTargetObject(proxy);
+ }
+ } catch (Exception e) {
+ log.error(">>> 获取代理对象异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ return null;
+ }
+ }
+
+ private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
+ Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
+ h.setAccessible(true);
+ Object dynamicAdvisedInterceptor = h.get(proxy);
+ Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
+ advised.setAccessible(true);
+ return ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
+ }
+
+ private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
+ Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
+ h.setAccessible(true);
+ AopProxy aopProxy = (AopProxy) h.get(proxy);
+ Field advised = aopProxy.getClass().getDeclaredField("advised");
+ advised.setAccessible(true);
+ return ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/HttpServletUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/HttpServletUtil.java
new file mode 100644
index 00000000..93aaf6b9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/HttpServletUtil.java
@@ -0,0 +1,72 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.util;
+
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * HttpServlet工具类,获取当前request和response
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:09
+ */
+public class HttpServletUtil {
+
+ /**
+ * 获取当前请求的request对象
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:10
+ */
+ public static HttpServletRequest getRequest() {
+ ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (requestAttributes == null) {
+ throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
+ } else {
+ return requestAttributes.getRequest();
+ }
+ }
+
+ /**
+ * 获取当前请求的response对象
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:10
+ */
+ public static HttpServletResponse getResponse() {
+ ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (requestAttributes == null) {
+ throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
+ } else {
+ return requestAttributes.getResponse();
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/IpAddressUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/IpAddressUtil.java
new file mode 100644
index 00000000..4541a1d7
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/IpAddressUtil.java
@@ -0,0 +1,108 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.core.net.NetUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.context.requestno.RequestNoContext;
+import com.alibaba.fastjson.JSONPath;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * 根据ip地址定位工具类,使用高德地地图定位api
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 11:25
+ */
+public class IpAddressUtil {
+
+ private static final Log log = Log.get();
+
+ private static final String LOCAL_IP = "127.0.0.1";
+
+ private static final String LOCAL_REMOTE_HOST = "0:0:0:0:0:0:0:1";
+
+ /**
+ * 获取客户端ip
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 9:32
+ */
+ public static String getIp(HttpServletRequest request) {
+ if (ObjectUtil.isEmpty(request)) {
+ return LOCAL_IP;
+ } else {
+ String remoteHost = ServletUtil.getClientIP(request);
+ return LOCAL_REMOTE_HOST.equals(remoteHost) ? LOCAL_IP : remoteHost;
+ }
+ }
+
+ /**
+ * 根据ip地址定位
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 15:17
+ */
+ @SuppressWarnings("unchecked")
+ public static String getAddress(HttpServletRequest request) {
+ String resultJson = SymbolConstant.DASH;
+
+ String ip = getIp(request);
+
+ //如果是本地ip或局域网ip,则直接不查询
+ if (ObjectUtil.isEmpty(ip) || NetUtil.isInnerIP(ip)) {
+ return resultJson;
+ }
+
+ try {
+ //获取阿里云定位api接口
+ String api = ConstantContextHolder.getIpGeoApi();
+ //获取阿里云定位appCode
+ String appCode = ConstantContextHolder.getIpGeoAppCode();
+ if (ObjectUtil.isAllNotEmpty(api, appCode)) {
+ String path = "$['data']['country','region','city','isp']";
+ String appCodeSymbol = "APPCODE";
+ HttpRequest http = HttpUtil.createGet(String.format(api, ip));
+ http.header(CommonConstant.AUTHORIZATION, appCodeSymbol + " " + appCode);
+ resultJson = http.timeout(3000).execute().body();
+ resultJson = String.join("", (List) JSONPath.read(resultJson, path));
+ }
+ } catch (Exception e) {
+ resultJson = SymbolConstant.DASH;
+ log.error(">>> 根据ip定位异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ }
+ return resultJson;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/JoinPointUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/JoinPointUtil.java
new file mode 100644
index 00000000..5a485afe
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/JoinPointUtil.java
@@ -0,0 +1,73 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import org.aspectj.lang.JoinPoint;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Spring切面工具类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 17:56
+ */
+public class JoinPointUtil {
+
+ /**
+ * 获取切面的参数json
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 17:57
+ */
+ public static String getArgsJsonString(JoinPoint joinPoint) {
+ StringBuilder argsJson = new StringBuilder();
+ Object[] args = joinPoint.getArgs();
+ for (Object arg : args) {
+ if (!isFilterObject(arg)) {
+ if (ObjectUtil.isNotNull(arg)) {
+ String jsonStr = JSON.toJSONString(arg);
+ argsJson.append(jsonStr).append(" ");
+ }
+ }
+ }
+ return argsJson.toString().trim();
+ }
+
+ /**
+ * 判断是否需要拼接参数,过滤掉HttpServletRequest,MultipartFile,HttpServletResponse等类型参数
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 17:59
+ */
+ private static boolean isFilterObject(Object arg) {
+ return arg instanceof MultipartFile || arg instanceof HttpServletRequest || arg instanceof HttpServletResponse;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/LibreOfficeUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/LibreOfficeUtil.java
new file mode 100644
index 00000000..9a1100d5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/LibreOfficeUtil.java
@@ -0,0 +1,113 @@
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.extra.spring.SpringUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.consts.MediaTypeConstant;
+import com.cn.xiaonuo.core.enums.DocumentFormatEnum;
+import com.cn.xiaonuo.core.exception.LibreOfficeException;
+import org.jodconverter.DocumentConverter;
+import org.jodconverter.document.DocumentFormat;
+import org.jodconverter.office.OfficeException;
+import org.springframework.http.MediaType;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * LibreOffice工具类,用于将word,excel,ppt等格式文件转为pdf预览
+ *
+ * @author xuyuxiang
+ * @date 2020/7/6 14:55
+ */
+public class LibreOfficeUtil {
+
+ private static final Log log = Log.get();
+
+ private static DocumentConverter documentConverter;
+
+ private static void init() {
+ try {
+ documentConverter = SpringUtil.getBean(DocumentConverter.class);
+ } catch (Exception e) {
+ throw new LibreOfficeException();
+ }
+ }
+
+ /**
+ * 将文件流转换为PDF流
+ *
+ * @param inputStream:输入流
+ * @param outputStream:输入pdf流
+ * @param fileSuffix:源文件后缀
+ * @return 目标类型的contentType
+ * @author xuyuxiang
+ * @date 2020/7/6 15:02
+ */
+ public static void convertToPdf(InputStream inputStream, OutputStream outputStream, String fileSuffix) {
+ init();
+ final DocumentFormatEnum documentFormatEnum = DocumentFormatEnum.valueOf(fileSuffix.toUpperCase());
+ final DocumentFormat format = documentFormatEnum.getFormFormat();
+ log.info(">>> 待转换的文档类型:{}", format);
+ final DocumentFormat targetFormat = documentFormatEnum.getTargetFormat();
+ log.info(">>> 转换的目标文档类型:{}", targetFormat);
+ try {
+ final InputStream is = documentFormatEnum.getInputStream(inputStream);
+ documentConverter.convert(is).as(format).to(outputStream).as(targetFormat).execute();
+ } catch (IOException | OfficeException e) {
+ e.printStackTrace();
+ }
+ log.info(">>> 文件转换结束");
+ }
+
+ /**
+ * 根据文件后缀判断是否图片
+ *
+ * @author xuyuxiang
+ * @date 2020/7/6 15:31
+ */
+ public static boolean isPic(String fileSuffix) {
+ return MediaTypeConstant.IMG_JPG.equals(fileSuffix)
+ || MediaTypeConstant.IMG_JPEG.equals(fileSuffix)
+ || MediaTypeConstant.IMG_PNG.equals(fileSuffix)
+ || MediaTypeConstant.IMG_GIF.equals(fileSuffix)
+ || MediaTypeConstant.IMG_TIF.equals(fileSuffix)
+ || MediaTypeConstant.IMG_BMP.equals(fileSuffix);
+ }
+
+ /**
+ * 根据文件后缀判断是否文档
+ *
+ * @author xuyuxiang
+ * @date 2020/7/6 15:31
+ */
+ public static boolean isDoc(String fileSuffix) {
+ return MediaTypeConstant.DOC_TXT.equals(fileSuffix)
+ || MediaTypeConstant.DOC_DOC.equals(fileSuffix)
+ || MediaTypeConstant.DOC_DOCX.equals(fileSuffix)
+ || MediaTypeConstant.DOC_XLS.equals(fileSuffix)
+ || MediaTypeConstant.DOC_XLSX.equals(fileSuffix)
+ || MediaTypeConstant.DOC_PPT.equals(fileSuffix)
+ || MediaTypeConstant.DOC_PPTX.equals(fileSuffix);
+ }
+
+ /**
+ * 根据文件后缀获取转换目标类型
+ *
+ * @author xuyuxiang
+ * @date 2020/7/6 17:03
+ */
+ public static String getTargetContentTypeBySuffix(String fileSuffix) {
+ //如果目标类型是pdf
+ if (MediaTypeConstant.DOC_TXT.equals(fileSuffix)
+ || MediaTypeConstant.DOC_DOC.equals(fileSuffix)
+ || MediaTypeConstant.DOC_DOCX.equals(fileSuffix)
+ || MediaTypeConstant.DOC_PPT.equals(fileSuffix)
+ || MediaTypeConstant.DOC_PPTX.equals(fileSuffix)) {
+ return MediaType.APPLICATION_PDF_VALUE;
+ } else {
+ //否则是html类型
+ return MediaType.TEXT_HTML_VALUE;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PageUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PageUtil.java
new file mode 100644
index 00000000..0594bc5c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PageUtil.java
@@ -0,0 +1,37 @@
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.convert.Convert;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import java.util.List;
+
+/**
+ * 分页工具类针对hutool分页的扩展
+ *
+ * @author xuyuxiang
+ * @date 2020/9/19 10:30
+ **/
+public class PageUtil extends cn.hutool.core.util.PageUtil{
+
+ /**
+ * 逻辑分页
+ *
+ * @author xuyuxiang
+ * @date 2020/9/19 10:36
+ **/
+ public static List page(Page page, List list) {
+ setFirstPageNo(1);
+ int start = getStart(Convert.toInt(page.getCurrent()), Convert.toInt(page.getSize()));
+ int end = getEnd(Convert.toInt(page.getCurrent()), Convert.toInt(page.getSize()));
+ if(start > list.size()) {
+ return CollectionUtil.newArrayList();
+ }else if(start > end) {
+ return CollectionUtil.newArrayList();
+ } else if(end > list.size()) {
+ return list.subList(start, list.size());
+ } else {
+ return list.subList(start, end);
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PastTimeFormatUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PastTimeFormatUtil.java
new file mode 100644
index 00000000..f3d39167
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PastTimeFormatUtil.java
@@ -0,0 +1,149 @@
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUnit;
+import cn.hutool.core.date.DateUtil;
+
+import java.util.Date;
+
+/**
+ * 过去时间格式化工具类
+ *
+ * @author xuyuxiang
+ * @date 2020/8/6 14:29
+ **/
+public class PastTimeFormatUtil {
+
+ private static final long ONE_MINUTE_SECONDS = 60;
+
+ private static final int BEFORE_DAWN_HOUR = 6;
+
+ private static final int MORNING_END_HOUR = 12;
+
+ private static final int NOON_END_HOUR = 13;
+
+ private static final int AFTERNOON_END_HOUR = 18;
+
+ private static final int NIGHT_END_HOUR = 24;
+
+ /**
+ * 将日期格式化为仿微信的日期
+ *
+ * @param date 要格式化的日期
+ * @return 格式化结果
+ * @author xuyuxiang
+ * @date 2020/8/6 11:41
+ **/
+ public static String formatPastTime(Date date) {
+ if (DateUtil.between(date, DateUtil.date(), DateUnit.SECOND, false) < 0) {
+ //今天之后的时间显示年月日时分
+ return DateUtil.format(date, DatePattern.NORM_DATETIME_MINUTE_PATTERN);
+ } else {
+ //如果是今年
+ if (DateUtil.thisYear() == DateUtil.year(date)) {
+ //如果是今天
+ if (DateUtil.isSameDay(date, DateUtil.date())) {
+ //相差分钟数
+ long betweenMinute = DateUtil.between(date, DateUtil.date(), DateUnit.MINUTE);
+ //如果在1小时之内
+ if (betweenMinute < ONE_MINUTE_SECONDS) {
+ //一分钟之内,显示刚刚
+ if (betweenMinute < 1) {
+ return "刚刚";
+ } else {
+ //一分钟之外,显示xx分钟前
+ return betweenMinute + "分钟前";
+ }
+ } else {
+ //一小时之外,显示时分
+ return getTodayHour(date) + " " + DateUtil.format(date, "HH:mm");
+ }
+ } else if (DateUtil.isSameDay(date, DateUtil.yesterday())) {
+ //如果是昨天,显示昨天时分
+ return "昨天 " + DateUtil.format(date, "HH:mm");
+ } else if (isThisWeek(date)) {
+ //如果是本周
+ String weekday;
+ //获取是本周的第几天
+ int dayOfWeek = DateUtil.dayOfWeek(date) - 1;
+ switch (dayOfWeek) {
+ case 1:
+ weekday = "周一";
+ break;
+ case 2:
+ weekday = "周二";
+ break;
+ case 3:
+ weekday = "周三";
+ break;
+ case 4:
+ weekday = "周四";
+ break;
+ case 5:
+ weekday = "周五";
+ break;
+ case 6:
+ weekday = "周六";
+ break;
+ default:
+ weekday = "周日";
+ break;
+ }
+ //显示本周时分
+ return weekday + " " + DateUtil.format(date, "HH:mm");
+ } else {
+ //否则显示月日时分
+ return DateUtil.format(date, "MM-dd HH:mm");
+ }
+ } else {
+ //本年之外显示年月日时分
+ return DateUtil.format(date, DatePattern.NORM_DATETIME_MINUTE_PATTERN);
+ }
+ }
+ }
+
+ /**
+ * 判断日期是否是本周
+ *
+ * @param date 要判断的日期
+ * @return boolean
+ * @author xuyuxiang
+ * @date 2020/8/6 12:10
+ **/
+ private static boolean isThisWeek(Date date) {
+ //获取本周开始时间
+ DateTime beginOfWeek = DateUtil.beginOfWeek(DateUtil.date());
+ //获取与本周开始时间相差的天数
+ long betweenBegin = DateUtil.between(date, beginOfWeek, DateUnit.DAY, false) + 1;
+ //如果是同一天,或相差天数小于0,则是本周
+ return DateUtil.isSameDay(date, beginOfWeek) || betweenBegin < 0;
+ }
+
+ /**
+ * 根据今天日期获取早中晚
+ *
+ * @author xuyuxiang
+ * @date 2020/8/6 14:42
+ **/
+ private static String getTodayHour(Date date) {
+ String result = "";
+ int hour = DateUtil.hour(date, true);
+ if (hour >= 0 && hour <= BEFORE_DAWN_HOUR) {
+ result = "凌晨";
+ }
+ if (hour > BEFORE_DAWN_HOUR && hour < MORNING_END_HOUR) {
+ result = "上午";
+ }
+ if (hour == MORNING_END_HOUR) {
+ result = "中午";
+ }
+ if (hour >= NOON_END_HOUR && hour <= AFTERNOON_END_HOUR) {
+ result = "下午";
+ }
+ if (hour > AFTERNOON_END_HOUR && hour <= NIGHT_END_HOUR) {
+ result = "晚上";
+ }
+ return result;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PoiUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PoiUtil.java
new file mode 100644
index 00000000..4e759a67
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/PoiUtil.java
@@ -0,0 +1,160 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.util;
+
+import cn.afterturn.easypoi.excel.ExcelExportUtil;
+import cn.afterturn.easypoi.excel.ExcelImportUtil;
+import cn.afterturn.easypoi.excel.entity.ExportParams;
+import cn.afterturn.easypoi.excel.entity.ImportParams;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.log.Log;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 简单导入导出工具类
+ *
+ * @author xuyuxiang
+ * @date 2020/6/30 17:25
+ */
+public class PoiUtil {
+
+ private static final Log log = Log.get();
+
+ /**
+ * 使用流的方式导出excel
+ *
+ * @param excelName 要导出的文件名称,如Users.xls
+ * @param pojoClass Excel实体类
+ * @param data 要导出的数据集合
+ * @author xuyuxiang
+ * @date 2020/7/1 10:00
+ */
+ public static void exportExcelWithStream(String excelName, Class> pojoClass, Collection> data) {
+ try {
+ HttpServletResponse response = HttpServletUtil.getResponse();
+ String fileName = URLEncoder.encode(excelName, CharsetUtil.UTF_8);
+ response.reset();
+ response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
+ response.setContentType("application/octet-stream;charset=UTF-8");
+ ServletOutputStream outputStream = response.getOutputStream();
+ Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), pojoClass, data);
+ workbook.write(outputStream);
+ outputStream.close();
+ } catch (IOException e) {
+ log.error(">>> 导出数据异常:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 使用文件的方式导出excel
+ *
+ * @param filePath 文件路径,如 d:/demo/demo.xls
+ * @param pojoClass Excel实体类
+ * @param data 要导出的数据集合
+ * @author xuyuxiang
+ * @date 2020/7/1 9:58
+ */
+ public static void exportExcelWithFile(String filePath, Class pojoClass, Collection data) {
+
+ try {
+ //先创建父文件夹
+ FileUtil.mkParentDirs(filePath);
+ File file = FileUtil.file(filePath);
+ Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), pojoClass, data);
+ FileOutputStream fos = new FileOutputStream(file);
+ workbook.write(fos);
+ fos.close();
+ } catch (IOException e) {
+ log.error(">>> 导出数据异常:{}", e.getMessage());
+ }
+
+ }
+
+ /**
+ * 根据文件路径来导入Excel
+ *
+ * @param filePath 文件路径
+ * @param titleRows 表标题的行数
+ * @param headerRows 表头行数
+ * @param pojoClass Excel实体类
+ * @author xuyuxiang
+ * @date 2020/7/1 9:58
+ */
+ public static List importExcel(String filePath, Integer titleRows, Integer headerRows, Class pojoClass) {
+ //判断文件是否存在
+ if (ObjectUtil.isEmpty(filePath)) {
+ return null;
+ }
+ ImportParams params = new ImportParams();
+ params.setTitleRows(titleRows);
+ params.setHeadRows(headerRows);
+ List list = null;
+ try {
+ list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
+ } catch (Exception e) {
+ log.error(">>> 导入数据异常:{}", e.getMessage());
+ }
+ return list;
+ }
+
+ /**
+ * 根据接收的Excel文件来导入Excel,并封装成实体类
+ *
+ * @param file 上传的文件
+ * @param titleRows 表标题的行数
+ * @param headerRows 表头行数
+ * @param pojoClass Excel实体类
+ * @author xuyuxiang
+ * @date 2020/7/1 9:57
+ */
+ public static List importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class pojoClass) {
+ if (ObjectUtil.isNull(file)) {
+ return null;
+ }
+ ImportParams params = new ImportParams();
+ params.setTitleRows(titleRows);
+ params.setHeadRows(headerRows);
+ List list = null;
+ try {
+ list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
+ } catch (Exception e) {
+ log.error(">>> 导入数据异常:{}", e.getMessage());
+ }
+ return list;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/ResponseUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/ResponseUtil.java
new file mode 100644
index 00000000..e0aa1a6c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/ResponseUtil.java
@@ -0,0 +1,73 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.http.ContentType;
+import com.cn.xiaonuo.core.pojo.response.ErrorResponseData;
+import com.alibaba.fastjson.JSON;
+import com.cn.xiaonuo.core.pojo.response.ErrorResponseData;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 响应工具类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 11:17
+ */
+public class ResponseUtil {
+
+ /**
+ * 响应异常,直接向前端写response,用于异常处理器捕获不到时手动抛出
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 11:18
+ */
+ public static void responseExceptionError(HttpServletResponse response,
+ Integer code,
+ String message,
+ String exceptionClazz) throws IOException {
+ response.setCharacterEncoding(CharsetUtil.UTF_8);
+ response.setContentType(ContentType.JSON.toString());
+ ErrorResponseData errorResponseData = new ErrorResponseData(code, message);
+ errorResponseData.setExceptionClazz(exceptionClazz);
+ String errorResponseJsonData = JSON.toJSONString(errorResponseData);
+ response.getWriter().write(errorResponseJsonData);
+ }
+
+ /**
+ * 响应异常,向前端返回ErrorResponseData的json数据,用于全局异常处理器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 11:31
+ */
+ public static ErrorResponseData responseDataError(Integer code, String message, String exceptionClazz) {
+ ErrorResponseData errorResponseData = new ErrorResponseData(code, message);
+ errorResponseData.setExceptionClazz(exceptionClazz);
+ return errorResponseData;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/UaUtil.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/UaUtil.java
new file mode 100644
index 00000000..8d32abb6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/util/UaUtil.java
@@ -0,0 +1,96 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.util;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.http.useragent.Browser;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 用户代理工具类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:52
+ */
+public class UaUtil {
+
+ /**
+ * 获取客户端浏览器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:53
+ */
+ public static String getBrowser(HttpServletRequest request) {
+ UserAgent userAgent = getUserAgent(request);
+ if (ObjectUtil.isEmpty(userAgent)) {
+ return SymbolConstant.DASH;
+ } else {
+ String browser = userAgent.getBrowser().toString();
+ return CommonConstant.UNKNOWN.equals(browser) ? SymbolConstant.DASH : browser;
+ }
+ }
+
+ /**
+ * 获取客户端操作系统
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:53
+ */
+ public static String getOs(HttpServletRequest request) {
+ UserAgent userAgent = getUserAgent(request);
+ if (ObjectUtil.isEmpty(userAgent)) {
+ return SymbolConstant.DASH;
+ } else {
+ String os = userAgent.getOs().toString();
+ return CommonConstant.UNKNOWN.equals(os) ? SymbolConstant.DASH : os;
+ }
+ }
+
+ /**
+ * 获取请求代理头
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:54
+ */
+ private static UserAgent getUserAgent(HttpServletRequest request) {
+ String userAgentStr = ServletUtil.getHeaderIgnoreCase(request, CommonConstant.USER_AGENT);
+ UserAgent userAgent = UserAgentUtil.parse(userAgentStr);
+ //判空
+ if (ObjectUtil.isNotEmpty(userAgentStr)) {
+ //如果根本没获取到浏览器
+ if (CommonConstant.UNKNOWN.equals(userAgent.getBrowser().getName())) {
+ //则将ua设置为浏览器
+ userAgent.setBrowser(new Browser(userAgentStr, null, ""));
+ }
+ }
+ return userAgent;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/date/DateValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/date/DateValue.java
new file mode 100644
index 00000000..5c63e91a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/date/DateValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.date;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期格式 yyyy-MM-dd
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = DateValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DateValue {
+
+ String message() default "日期格式不正确,正确格式应为yyyy-MM-dd";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ DateValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/date/DateValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/date/DateValueValidator.java
new file mode 100644
index 00000000..06bd08bf
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/date/DateValueValidator.java
@@ -0,0 +1,59 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.date;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期格式 yyyy-MM-dd
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class DateValueValidator implements ConstraintValidator {
+
+ @Override
+ public boolean isValid(String dateValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateValue.length() != DatePattern.NORM_DATE_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parseDate(dateValue);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateordatetime/DateOrDateTimeValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateordatetime/DateOrDateTimeValue.java
new file mode 100644
index 00000000..5f0cb72e
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateordatetime/DateOrDateTimeValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dateordatetime;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期或时间格式 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = DateOrDateTimeValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DateOrDateTimeValue {
+
+ String message() default "日期或时间格式不正确,正确格式应为yyyy-MM-dd或yyyy-MM-dd HH:mm:ss";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ DateOrDateTimeValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateordatetime/DateOrDateTimeValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateordatetime/DateOrDateTimeValueValidator.java
new file mode 100644
index 00000000..d76a0e0d
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateordatetime/DateOrDateTimeValueValidator.java
@@ -0,0 +1,65 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dateordatetime;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期或时间格式 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class DateOrDateTimeValueValidator implements ConstraintValidator {
+
+ @Override
+ public boolean isValid(String dateValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateValue.length() != DatePattern.NORM_DATE_PATTERN.length() &&
+ dateValue.length() != DatePattern.NORM_DATETIME_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parseDate(dateValue);
+ return true;
+ } catch (Exception dateParseException) {
+ try {
+ DateUtil.parseDateTime(dateValue);
+ return true;
+ } catch (Exception dateTimeParseException) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateormonth/DateOrMonthValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateormonth/DateOrMonthValue.java
new file mode 100644
index 00000000..893802af
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateormonth/DateOrMonthValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dateormonth;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期格式 yyyy-MM-dd 或 yyyy-MM
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = DateOrMonthValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DateOrMonthValue {
+
+ String message() default "日期格式不正确,正确格式应为yyyy-MM-dd或yyyy-MM";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ DateOrMonthValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateormonth/DateOrMonthValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateormonth/DateOrMonthValueValidator.java
new file mode 100644
index 00000000..88f1b07c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateormonth/DateOrMonthValueValidator.java
@@ -0,0 +1,67 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dateormonth;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期格式 yyyy-MM-dd 或 yyyy-MM
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class DateOrMonthValueValidator implements ConstraintValidator {
+
+ public static final String NORM_MONTH_PATTERN = "yyyy-MM";
+
+ @Override
+ public boolean isValid(String dateValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateValue.length() != DatePattern.NORM_DATE_PATTERN.length() &&
+ dateValue.length() != NORM_MONTH_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parseDate(dateValue);
+ return true;
+ } catch (Exception dateParseException) {
+ try {
+ DateUtil.parse(dateValue, NORM_MONTH_PATTERN);
+ return true;
+ } catch (Exception monthParseException) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateortime/DateOrTimeValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateortime/DateOrTimeValue.java
new file mode 100644
index 00000000..5a6ddd9c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateortime/DateOrTimeValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dateortime;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期或时间格式 yyyy-MM-dd 或 HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = DateOrTimeValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DateOrTimeValue {
+
+ String message() default "日期或时间格式不正确,正确格式应为yyyy-MM-dd 或 HH:mm:ss";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ DateOrTimeValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateortime/DateOrTimeValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateortime/DateOrTimeValueValidator.java
new file mode 100644
index 00000000..845616f6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dateortime/DateOrTimeValueValidator.java
@@ -0,0 +1,65 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dateortime;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期或时间格式 yyyy-MM-dd 或 HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class DateOrTimeValueValidator implements ConstraintValidator {
+
+ @Override
+ public boolean isValid(String dateValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateValue.length() != DatePattern.NORM_DATE_PATTERN.length() &&
+ dateValue.length() != DatePattern.NORM_TIME_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parseDate(dateValue);
+ return true;
+ } catch (Exception dateParseException) {
+ try {
+ DateUtil.parseTime(dateValue);
+ return true;
+ } catch (Exception timeParseException) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/datetime/DateTimeValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/datetime/DateTimeValue.java
new file mode 100644
index 00000000..52c5e9a2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/datetime/DateTimeValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.datetime;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期时间格式 yyyy-MM-dd HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = DateTimeValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DateTimeValue {
+
+ String message() default "日期时间格式不正确,正确格式应为yyyy-MM-dd HH:mm:ss";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ DateTimeValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/datetime/DateTimeValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/datetime/DateTimeValueValidator.java
new file mode 100644
index 00000000..734fd5ed
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/datetime/DateTimeValueValidator.java
@@ -0,0 +1,59 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.datetime;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期时间格式 yyyy-MM-dd HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class DateTimeValueValidator implements ConstraintValidator {
+
+ @Override
+ public boolean isValid(String dateTimeValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateTimeValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateTimeValue.length() != DatePattern.NORM_DATETIME_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parseDateTime(dateTimeValue);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dict/DictValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dict/DictValue.java
new file mode 100644
index 00000000..dbac78c1
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dict/DictValue.java
@@ -0,0 +1,66 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dict;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 检验值是否为字典值,验证sys_dict_data表中有没有相关的字典项
+ *
+ * 本注解用的时候,一定要加dictType参数,用来表明验证的哪个字典类型中的值
+ *
+ * dictType值来自数据库中sys_dict_type表的code值
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 23:49
+ */
+@Documented
+@Constraint(validatedBy = DictValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DictValue {
+
+ String message() default "不正确的字典值,请检查数据库中是否录入该字典项";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ /**
+ * 字典的类型
+ */
+ String[] dictType();
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ DictValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dict/DictValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dict/DictValueValidator.java
new file mode 100644
index 00000000..af4753b5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/dict/DictValueValidator.java
@@ -0,0 +1,58 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.dict;
+
+import com.cn.xiaonuo.core.context.system.SystemContextHolder;
+import com.cn.xiaonuo.core.context.system.SystemContextHolder;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.util.List;
+
+/**
+ * 字典值校验
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 23:49
+ */
+public class DictValueValidator implements ConstraintValidator {
+
+ private String[] dictType;
+
+ @Override
+ public void initialize(DictValue constraintAnnotation) {
+ this.dictType = constraintAnnotation.dictType();
+ }
+
+ @Override
+ public boolean isValid(String dictValue, ConstraintValidatorContext context) {
+ List dictCodes = SystemContextHolder.me().getDictCodesByDictTypeCode(dictType);
+ if (dictCodes != null && dictCodes.size() > 0) {
+ return dictCodes.contains(dictValue);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/flag/FlagValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/flag/FlagValue.java
new file mode 100644
index 00000000..d198e6b2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/flag/FlagValue.java
@@ -0,0 +1,62 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.flag;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验标识,只有Y和N两种状态的标识
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 23:49
+ */
+@Documented
+@Constraint(validatedBy = FlagValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FlagValue {
+
+ String message() default "不正确的状态标识,请传递Y或者N";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ /**
+ * 是否必填
+ */
+ boolean required() default true;
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ FlagValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/flag/FlagValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/flag/FlagValueValidator.java
new file mode 100644
index 00000000..ed896559
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/flag/FlagValueValidator.java
@@ -0,0 +1,65 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.flag;
+
+import cn.hutool.core.util.StrUtil;
+import com.cn.xiaonuo.core.enums.YesOrNotEnum;
+import com.cn.xiaonuo.core.enums.YesOrNotEnum;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验标识,只有Y和N两种状态的标识
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 23:49
+ */
+public class FlagValueValidator implements ConstraintValidator {
+
+ private Boolean required;
+
+ @Override
+ public void initialize(FlagValue constraintAnnotation) {
+ this.required = constraintAnnotation.required();
+ }
+
+ @Override
+ public boolean isValid(String flagValue, ConstraintValidatorContext context) {
+
+ // 如果是必填的
+ if (required) {
+ return YesOrNotEnum.Y.getCode().equals(flagValue) || YesOrNotEnum.N.getCode().equals(flagValue);
+ } else {
+
+ //如果不是必填,可以为空
+ if (StrUtil.isEmpty(flagValue)) {
+ return true;
+ } else {
+ return YesOrNotEnum.Y.getCode().equals(flagValue) || YesOrNotEnum.N.getCode().equals(flagValue);
+ }
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/month/MonthValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/month/MonthValue.java
new file mode 100644
index 00000000..1253fe82
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/month/MonthValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.month;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期格式 yyyy-MM
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = MonthValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MonthValue {
+
+ String message() default "日期格式不正确,正确格式应为yyyy-MM";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ MonthValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/month/MonthValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/month/MonthValueValidator.java
new file mode 100644
index 00000000..0bc1de5f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/month/MonthValueValidator.java
@@ -0,0 +1,60 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.month;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期格式 yyyy-MM
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class MonthValueValidator implements ConstraintValidator {
+
+ public static final String NORM_MONTH_PATTERN = "yyyy-MM";
+
+ @Override
+ public boolean isValid(String dateValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateValue.length() != NORM_MONTH_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parse(dateValue, NORM_MONTH_PATTERN);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/mothordatetime/MonthOrDateTimeValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/mothordatetime/MonthOrDateTimeValue.java
new file mode 100644
index 00000000..121cefb9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/mothordatetime/MonthOrDateTimeValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.mothordatetime;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期格式 yyyy-MM 或 yyyy-MM-dd HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = MonthOrDateTimeValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MonthOrDateTimeValue {
+
+ String message() default "日期格式不正确,正确格式应为yyyy-MM或yyyy-MM-dd HH:mm:ss";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ MonthOrDateTimeValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/mothordatetime/MonthOrDateTimeValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/mothordatetime/MonthOrDateTimeValueValidator.java
new file mode 100644
index 00000000..f1e375aa
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/mothordatetime/MonthOrDateTimeValueValidator.java
@@ -0,0 +1,67 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.mothordatetime;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期格式 yyyy-MM 或 yyyy-MM-dd HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class MonthOrDateTimeValueValidator implements ConstraintValidator {
+
+ public static final String NORM_MONTH_PATTERN = "yyyy-MM";
+
+ @Override
+ public boolean isValid(String dateValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateValue.length() != DatePattern.NORM_DATETIME_PATTERN.length() &&
+ dateValue.length() != NORM_MONTH_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parseDateTime(dateValue);
+ return true;
+ } catch (Exception dateTimeParseException) {
+ try {
+ DateUtil.parse(dateValue, NORM_MONTH_PATTERN);
+ return true;
+ } catch (Exception monthParseException) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/time/TimeValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/time/TimeValue.java
new file mode 100644
index 00000000..4e7ca5a4
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/time/TimeValue.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.time;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 校验日期格式 HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+@Documented
+@Constraint(validatedBy = TimeValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TimeValue {
+
+ String message() default "日期格式不正确,正确格式应为HH:mm:ss";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ TimeValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/time/TimeValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/time/TimeValueValidator.java
new file mode 100644
index 00000000..c1b551e6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/time/TimeValueValidator.java
@@ -0,0 +1,59 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.time;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 校验日期格式 HH:mm:ss
+ *
+ * @author xuyuxiang
+ * @date 2020/5/26 14:48
+ */
+public class TimeValueValidator implements ConstraintValidator {
+
+ @Override
+ public boolean isValid(String dateValue, ConstraintValidatorContext context) {
+ //为空则放过,因为在此校验之前会加入@NotNull或@NotBlank校验
+ if (ObjectUtil.isEmpty(dateValue)) {
+ return true;
+ }
+ //长度不对直接返回
+ if (dateValue.length() != DatePattern.NORM_TIME_PATTERN.length()) {
+ return false;
+ }
+ try {
+ DateUtil.parseTime(dateValue);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/unique/TableUniqueValue.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/unique/TableUniqueValue.java
new file mode 100644
index 00000000..5be93285
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/unique/TableUniqueValue.java
@@ -0,0 +1,88 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.unique;
+
+import com.cn.xiaonuo.core.consts.CommonConstant;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 验证表的的某个字段值是否在是唯一值
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 23:49
+ */
+@Documented
+@Constraint(validatedBy = TableUniqueValueValidator.class)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TableUniqueValue {
+
+ String message() default "库中存在重复编码,请更换该编码值";
+
+ Class[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ /**
+ * 表名称,例如 sys_user
+ */
+ String tableName();
+
+ /**
+ * 列名称,例如 user_code
+ */
+ String columnName();
+
+ /**
+ * 是否开启状态校验,默认是关闭的
+ *
+ * 关于为何开启状态校验:
+ *
+ * 若项目中某个表包含控制逻辑删除的字段,我们在进行唯一值校验的时候要排除这种状态的记录,所以需要用到这个功能
+ */
+ boolean excludeLogicDeleteItems() default false;
+
+ /**
+ * 标识状态的字段名
+ */
+ String logicDeleteFieldName() default CommonConstant.STATUS;
+
+ /**
+ * 逻辑删除的值(默认2是删除),用string是为了更通用
+ */
+ String logicDeleteValue() default CommonConstant.DEFAULT_LOGIC_DELETE_VALUE;
+
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
+ @Retention(RUNTIME)
+ @Documented
+ @interface List {
+ TableUniqueValue[] value();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/unique/TableUniqueValueValidator.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/unique/TableUniqueValueValidator.java
new file mode 100644
index 00000000..a9944829
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/validation/unique/TableUniqueValueValidator.java
@@ -0,0 +1,127 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.core.validation.unique;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.context.group.RequestGroupContext;
+import com.cn.xiaonuo.core.context.group.RequestParamIdContext;
+import com.cn.xiaonuo.core.context.system.SystemContextHolder;
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import com.cn.xiaonuo.core.pojo.base.validate.UniqueValidateParam;
+import com.cn.xiaonuo.core.context.group.RequestGroupContext;
+import com.cn.xiaonuo.core.context.group.RequestParamIdContext;
+import com.cn.xiaonuo.core.context.system.SystemContextHolder;
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import com.cn.xiaonuo.core.pojo.base.validate.UniqueValidateParam;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * 验证表的的某个字段值是否在是唯一值
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 23:49
+ */
+public class TableUniqueValueValidator implements ConstraintValidator {
+
+ private String tableName;
+
+ private String columnName;
+
+ private boolean excludeLogicDeleteItems;
+
+ private String logicDeleteFieldName;
+
+ private String logicDeleteValue;
+
+ @Override
+ public void initialize(TableUniqueValue constraintAnnotation) {
+ this.tableName = constraintAnnotation.tableName();
+ this.columnName = constraintAnnotation.columnName();
+ this.excludeLogicDeleteItems = constraintAnnotation.excludeLogicDeleteItems();
+ this.logicDeleteFieldName = constraintAnnotation.logicDeleteFieldName();
+ this.logicDeleteValue = constraintAnnotation.logicDeleteValue();
+ }
+
+ @Override
+ public boolean isValid(String fieldValue, ConstraintValidatorContext context) {
+
+ if (ObjectUtil.isNull(fieldValue)) {
+ return true;
+ }
+
+ Class> validateGroupClass = RequestGroupContext.get();
+
+ // 如果属于add group,则校验库中所有行
+ if (BaseParam.add.class.equals(validateGroupClass)) {
+ return SystemContextHolder.me().tableUniValueFlag(createAddParam(fieldValue));
+ }
+
+ // 如果属于edit group,校验时需要排除当前修改的这条记录
+ if (BaseParam.edit.class.equals(validateGroupClass)) {
+ return SystemContextHolder.me().tableUniValueFlag(createEditParam(fieldValue));
+ }
+
+ // 默认校验所有的行
+ return SystemContextHolder.me().tableUniValueFlag(createAddParam(fieldValue));
+ }
+
+ /**
+ * 创建校验新增的参数
+ *
+ * @author xuyuxiang
+ * @date 2020/8/17 21:55
+ */
+ private UniqueValidateParam createAddParam(String fieldValue) {
+ return UniqueValidateParam.builder()
+ .tableName(tableName)
+ .columnName(columnName)
+ .value(fieldValue)
+ .excludeCurrentRecord(Boolean.FALSE)
+ .excludeLogicDeleteItems(excludeLogicDeleteItems)
+ .logicDeleteFieldName(logicDeleteFieldName)
+ .logicDeleteValue(logicDeleteValue).build();
+ }
+
+ /**
+ * 创建修改的参数校验
+ *
+ * @author xuyuxiang
+ * @date 2020/8/17 21:56
+ */
+ private UniqueValidateParam createEditParam(String fieldValue) {
+ return UniqueValidateParam.builder()
+ .tableName(tableName)
+ .columnName(columnName)
+ .value(fieldValue)
+ .excludeCurrentRecord(Boolean.TRUE)
+ .id(RequestParamIdContext.get())
+ .excludeLogicDeleteItems(excludeLogicDeleteItems)
+ .logicDeleteFieldName(logicDeleteFieldName)
+ .logicDeleteValue(logicDeleteValue).build();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/web/XiaoNuoRequestResponseBodyMethodProcessor.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/web/XiaoNuoRequestResponseBodyMethodProcessor.java
new file mode 100644
index 00000000..5df88b96
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/web/XiaoNuoRequestResponseBodyMethodProcessor.java
@@ -0,0 +1,56 @@
+package com.cn.xiaonuo.core.web;
+
+import com.cn.xiaonuo.core.context.param.RequestParamContext;
+import org.springframework.core.Conventions;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.lang.Nullable;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.ModelAndViewContainer;
+import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
+import java.util.List;
+
+/**
+ * 拓展原有RequestResponseBodyMethodProcessor,只为缓存临时参数
+ *
+ * @author xuyuxiang
+ * @date 2020/8/21 20:51
+ */
+public class XiaoNuoRequestResponseBodyMethodProcessor extends RequestResponseBodyMethodProcessor {
+
+ public XiaoNuoRequestResponseBodyMethodProcessor(List> converters) {
+ super(converters);
+ }
+
+ @Override
+ public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
+
+ parameter = parameter.nestedIfOptional();
+ Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
+
+ // 临时缓存一下@RequestBody注解上的参数
+ RequestParamContext.setObject(arg);
+
+ String name = Conventions.getVariableNameForParameter(parameter);
+
+ if (binderFactory != null) {
+ WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
+ if (arg != null) {
+ validateIfApplicable(binder, parameter);
+ if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
+ throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
+ }
+ }
+ if (mavContainer != null) {
+ mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
+ }
+ }
+
+ return adaptArgumentIfNecessary(arg, parameter);
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/web/package-info.java b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/web/package-info.java
new file mode 100644
index 00000000..ea533af1
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-core/src/main/java/com/cn/xiaonuo/core/web/package-info.java
@@ -0,0 +1,4 @@
+package com.cn.xiaonuo.core.web;
+/**
+ * 此包存放的对spring mvc的一些拓展
+ */
diff --git a/xiaonuo-base/xiaonuo-system/README.md b/xiaonuo-base/xiaonuo-system/README.md
new file mode 100644
index 00000000..aec68cad
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/README.md
@@ -0,0 +1 @@
+** 此模块可以尽量不要动,升级的时候只要将xiaonuo-base的模块覆盖即可 **
diff --git a/xiaonuo-base/xiaonuo-system/pom.xml b/xiaonuo-base/xiaonuo-system/pom.xml
new file mode 100644
index 00000000..4ad775e8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/pom.xml
@@ -0,0 +1,93 @@
+
+
+ 4.0.0
+
+
+ cn.xiaonuo
+ xiaonuo-base
+ 1.1.0
+ ../pom.xml
+
+
+ xiaonuo-system
+
+ jar
+
+
+
+
+
+ cn.xiaonuo
+ xiaonuo-core
+ 1.1.0
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+ com.vaadin.external.google
+ android-json
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+ true
+
+
+ io.lettuce
+ lettuce-core
+
+
+
+
+ redis.clients
+ jedis
+ true
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+
+
+
+
+ io.springfox
+ springfox-swagger2
+
+
+ io.springfox
+ springfox-swagger-ui
+
+
+ com.github.xiaoymin
+ swagger-bootstrap-ui
+
+
+
+
+ ${project.artifactId}
+
+
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/AopConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/AopConfig.java
new file mode 100644
index 00000000..ada184ba
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/AopConfig.java
@@ -0,0 +1,90 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import com.cn.xiaonuo.sys.core.aop.BusinessLogAop;
+import com.cn.xiaonuo.sys.core.aop.DataScopeAop;
+import com.cn.xiaonuo.sys.core.aop.PermissionAop;
+import com.cn.xiaonuo.sys.core.aop.WrapperAop;
+import com.cn.xiaonuo.sys.core.aop.BusinessLogAop;
+import com.cn.xiaonuo.sys.core.aop.DataScopeAop;
+import com.cn.xiaonuo.sys.core.aop.PermissionAop;
+import com.cn.xiaonuo.sys.core.aop.WrapperAop;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 切面配置
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 11:25
+ */
+@Configuration
+public class AopConfig {
+
+ /**
+ * 日志切面
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 14:10
+ */
+ @Bean
+ public BusinessLogAop businessLogAop() {
+ return new BusinessLogAop();
+ }
+
+ /**
+ * 权限切面
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 17:36
+ */
+ @Bean
+ public PermissionAop permissionAop() {
+ return new PermissionAop();
+ }
+
+ /**
+ * 数据范围切面
+ *
+ * @author xuyuxiang
+ * @date 2020/4/6 13:47
+ */
+ @Bean
+ public DataScopeAop dataScopeAop() {
+ return new DataScopeAop();
+ }
+
+ /**
+ * 结果包装的aop
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 22:18
+ */
+ @Bean
+ public WrapperAop wrapperAop() {
+ return new WrapperAop();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/CacheConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/CacheConfig.java
new file mode 100644
index 00000000..2ce0a588
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/CacheConfig.java
@@ -0,0 +1,98 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import cn.hutool.cache.CacheUtil;
+import cn.hutool.cache.impl.TimedCache;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.core.cache.MappingCache;
+import com.cn.xiaonuo.sys.core.cache.ResourceCache;
+import com.cn.xiaonuo.sys.core.cache.UserCache;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.core.cache.MappingCache;
+import com.cn.xiaonuo.sys.core.cache.ResourceCache;
+import com.cn.xiaonuo.sys.core.cache.UserCache;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Map;
+
+/**
+ * 缓存的配置,默认使用基于内存的缓存,如果分布式部署请更换为redis
+ *
+ * @author xuyuxiang
+ * @date 2020/7/9 11:43
+ */
+@Configuration
+public class CacheConfig {
+
+ /**
+ * url资源的缓存,默认不过期
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 11:44
+ */
+ @Bean
+ public ResourceCache resourceCache() {
+ return new ResourceCache();
+ }
+
+ /**
+ * 登录用户的缓存,默认过期时间,根据系统sys_config中的常量决定
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 11:44
+ */
+ @Bean
+ public UserCache userCache() {
+ TimedCache timedCache =
+ CacheUtil.newTimedCache(ConstantContextHolder.getSessionTokenExpireSec() * 1000);
+
+ // 定时清理缓存,间隔1秒
+ timedCache.schedulePrune(1000);
+
+ return new UserCache(timedCache);
+ }
+
+ /**
+ * mapping映射缓存
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 13:55
+ */
+ @Bean
+ public MappingCache mappingCache() {
+ TimedCache> timedCache =
+ CacheUtil.newTimedCache(2 * 60 * 1000);
+
+ // 定时清理缓存,间隔1秒
+ timedCache.schedulePrune(1000);
+
+ return new MappingCache(timedCache);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/DataSourceConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/DataSourceConfig.java
new file mode 100644
index 00000000..f3b9c0e5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/DataSourceConfig.java
@@ -0,0 +1,66 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.alibaba.druid.support.http.StatViewServlet;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import java.util.HashMap;
+
+/**
+ * Druid配置
+ *
+ * @author yubaoshan
+ * @date 2017/5/20 21:58
+ */
+@Configuration
+// @Import(MultiDataSourceConfig.class)
+public class DataSourceConfig {
+
+ /**
+ * druid监控,配置StatViewServlet
+ *
+ * @author xuyuxiang
+ * @date 2020/6/28 16:03
+ */
+ @Bean
+ public ServletRegistrationBean druidServletRegistration() {
+
+ // 设置servelet的参数
+ HashMap statViewServletParams = CollectionUtil.newHashMap();
+ statViewServletParams.put("resetEnable", "true");
+ statViewServletParams.put("loginUsername", ConstantContextHolder.getDruidMonitorUsername());
+ statViewServletParams.put("loginPassword", ConstantContextHolder.getDruidMonitorPassword());
+
+ ServletRegistrationBean registration = new ServletRegistrationBean<>(new StatViewServlet());
+ registration.addUrlMappings("/druid/*");
+ registration.setInitParameters(statViewServletParams);
+ return registration;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/FileConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/FileConfig.java
new file mode 100644
index 00000000..5de88d11
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/FileConfig.java
@@ -0,0 +1,72 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.file.FileOperator;
+import com.cn.xiaonuo.core.file.modular.local.LocalFileOperator;
+import com.cn.xiaonuo.core.file.modular.local.prop.LocalFileProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 文件存储的配置
+ *
+ * 默认激活本地文件存储
+ *
+ * @author yubaoshan
+ * @date 2020/6/6 22:27
+ */
+@Configuration
+public class FileConfig {
+
+ /**
+ * 默认文件存储的位置
+ */
+ public static final String DEFAULT_BUCKET = "defaultBucket";
+
+ /**
+ * 本地文件操作客户端
+ *
+ * @author yubaoshan
+ * @date 2020/6/9 21:39
+ */
+ @Bean
+ public FileOperator fileOperator() {
+ LocalFileProperties localFileProperties = new LocalFileProperties();
+ String fileUploadPathForWindows = ConstantContextHolder.getDefaultFileUploadPathForWindows();
+ if (ObjectUtil.isNotEmpty(fileUploadPathForWindows)) {
+ localFileProperties.setLocalFileSavePathWin(fileUploadPathForWindows);
+ }
+
+ String fileUploadPathForLinux = ConstantContextHolder.getDefaultFileUploadPathForLinux();
+ if (ObjectUtil.isNotEmpty(fileUploadPathForLinux)) {
+ localFileProperties.setLocalFileSavePathLinux(fileUploadPathForLinux);
+ }
+ return new LocalFileOperator(localFileProperties);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/MailSenderConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/MailSenderConfig.java
new file mode 100644
index 00000000..f4d96dcb
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/MailSenderConfig.java
@@ -0,0 +1,59 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.extra.mail.MailAccount;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.email.MailSender;
+import com.cn.xiaonuo.core.email.modular.SimpleMailSender;
+import com.cn.xiaonuo.core.pojo.email.EmailConfigs;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 邮件发送控制器
+ *
+ * @author yubaoshan
+ * @date 2020/6/6 22:27
+ */
+@Configuration
+public class MailSenderConfig {
+
+ /**
+ * 邮件发射器
+ *
+ * @author yubaoshan
+ * @date 2020/6/9 23:13
+ */
+ @Bean
+ public MailSender mailSender() {
+ EmailConfigs emailConfigs = ConstantContextHolder.getEmailConfigs();
+ MailAccount mailAccount = new MailAccount();
+ BeanUtil.copyProperties(emailConfigs, mailAccount);
+ return new SimpleMailSender(mailAccount);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/MybatisConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/MybatisConfig.java
new file mode 100644
index 00000000..b2115c57
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/MybatisConfig.java
@@ -0,0 +1,92 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import com.cn.xiaonuo.sys.core.mybatis.dbid.XiaoNuoDatabaseIdProvider;
+import com.cn.xiaonuo.sys.core.mybatis.fieldfill.CustomMetaObjectHandler;
+import com.cn.xiaonuo.sys.core.mybatis.sqlfilter.DemoProfileSqlInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * mybatis扩展插件配置
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 10:49
+ */
+@Configuration
+@MapperScan(basePackages = {"com.cn.xiaonuo.**.mapper"})
+public class MybatisConfig {
+
+ /**
+ * mybatis-plus分页插件
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 15:42
+ */
+ @Bean
+ public PaginationInterceptor paginationInterceptor() {
+ return new PaginationInterceptor();
+ }
+
+ /**
+ * 演示环境的sql拦截器
+ *
+ * 演示环境只开放查询操作,其他都不允许
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 12:24
+ */
+ @Bean
+ public DemoProfileSqlInterceptor demoProfileSqlInterceptor() {
+ return new DemoProfileSqlInterceptor();
+ }
+
+ /**
+ * 自定义公共字段自动注入
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 15:42
+ */
+ @Bean
+ public MetaObjectHandler metaObjectHandler() {
+ return new CustomMetaObjectHandler();
+ }
+
+ /**
+ * 数据库id选择器
+ *
+ * @author yubaoshan
+ * @date 2020/6/20 21:23
+ */
+ @Bean
+ public XiaoNuoDatabaseIdProvider xiaoNuoDatabaseIdProvider() {
+ return new XiaoNuoDatabaseIdProvider();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SmsSenderConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SmsSenderConfig.java
new file mode 100644
index 00000000..d5c6a019
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SmsSenderConfig.java
@@ -0,0 +1,65 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.pojo.sms.AliyunSmsConfigs;
+import com.cn.xiaonuo.core.sms.SmsSender;
+import com.cn.xiaonuo.core.sms.modular.aliyun.AliyunSmsSender;
+import com.cn.xiaonuo.core.sms.modular.aliyun.msign.impl.MapBasedMultiSignManager;
+import com.cn.xiaonuo.core.sms.modular.aliyun.prop.AliyunSmsProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 短信发送配置,短信发送的配置属性都在数据库的sys_config表中
+ *
+ * 默认开启了阿里云的短信配置
+ *
+ * @author yubaoshan
+ * @date 2020/6/6 22:27
+ */
+@Configuration
+public class SmsSenderConfig {
+
+ /**
+ * 短信发送器(阿里云)
+ *
+ * @author yubaoshan
+ * @date 2020/6/6 22:30
+ */
+ @Bean
+ public SmsSender aliyunSmsSender() {
+
+ // 从数据库配置读取阿里云配置
+ AliyunSmsConfigs aliyunSmsConfigs = ConstantContextHolder.getAliyunSmsConfigs();
+ AliyunSmsProperties aliyunSmsProperties = new AliyunSmsProperties();
+ BeanUtil.copyProperties(aliyunSmsConfigs, aliyunSmsProperties);
+
+ return new AliyunSmsSender(new MapBasedMultiSignManager(), aliyunSmsProperties);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SpringSecurityConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SpringSecurityConfig.java
new file mode 100644
index 00000000..c68901e8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SpringSecurityConfig.java
@@ -0,0 +1,117 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import com.cn.xiaonuo.core.consts.SpringSecurityConstant;
+import com.cn.xiaonuo.sys.core.filter.security.JwtAuthenticationTokenFilter;
+import com.cn.xiaonuo.sys.core.filter.security.entrypoint.JwtAuthenticationEntryPoint;
+import com.cn.xiaonuo.sys.modular.auth.service.impl.AuthServiceImpl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+import javax.annotation.Resource;
+
+/**
+ * SpringSecurity配置
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 10:54
+ */
+@Configuration
+public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Resource
+ private AuthServiceImpl authService;
+
+ @Resource
+ private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
+
+ @Resource
+ private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
+
+ /**
+ * 开启跨域访问拦截器
+ *
+ * @author yubaoshan
+ * @date 2020/4/29 9:50
+ */
+ @Bean
+ public CorsFilter corsFilter() {
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.addAllowedOrigin("*");
+ corsConfiguration.addAllowedHeader("*");
+ corsConfiguration.addAllowedMethod("*");
+
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ source.registerCorsConfiguration("/**", corsConfiguration);
+ return new CorsFilter(source);
+ }
+
+ @Override
+ protected void configure(HttpSecurity httpSecurity) throws Exception {
+
+ //开启模拟请求,比如API POST测试工具的测试,不开启时,API POST为报403错误
+ httpSecurity.csrf().disable();
+
+ //开启跨域访问
+ httpSecurity.cors();
+
+ //不使用默认退出,自定义退出
+ httpSecurity.logout().disable();
+
+ //未授权时访问须授权的资源端点
+ httpSecurity.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
+
+ //放开一些接口的权限校验
+ for (String notAuthResource : SpringSecurityConstant.NONE_SECURITY_URL_PATTERNS) {
+ httpSecurity.authorizeRequests().antMatchers(notAuthResource).permitAll();
+ }
+
+ //其余的都需授权访问
+ httpSecurity.authorizeRequests().anyRequest().authenticated();
+
+ //前置token过滤器
+ httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
+
+ //用户详情service
+ httpSecurity.userDetailsService(authService);
+
+ //全局不创建session
+ httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+
+ //禁用页面缓存,返回的都是json
+ httpSecurity.headers()
+ .frameOptions().disable()
+ .cacheControl();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SwaggerConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SwaggerConfig.java
new file mode 100644
index 00000000..4a5dd951
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/SwaggerConfig.java
@@ -0,0 +1,89 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.List;
+
+/**
+ * swagger配置
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 15:05
+ */
+@Configuration
+@EnableSwagger2
+@EnableSwaggerBootstrapUI
+public class SwaggerConfig {
+
+ @Bean
+ public Docket createRestApi() {
+ Parameter parameter = new ParameterBuilder()
+ .name("Authorization")
+ .description("token令牌")
+ .modelRef(new ModelRef("string"))
+ .parameterType("header")
+ .required(false)
+ .build();
+
+ List parameters = CollectionUtil.newArrayList();
+ parameters.add(parameter);
+
+ return new Docket(DocumentationType.SWAGGER_2)
+ .apiInfo(apiInfo())
+ .select()
+ .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+ .paths(PathSelectors.any())
+ .build()
+ .globalOperationParameters(parameters);
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder()
+ .title("XiaoNuo Doc")
+ .description("XiaoNuo Doc文档")
+ .termsOfServiceUrl("https://www.xiaonuo.vip")
+ .contact(new Contact("xuyuxiang, yubaoshan", "https://www.xiaonuo.vip", ""))
+ .version("1.0")
+ .build();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/WebMvcConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/WebMvcConfig.java
new file mode 100644
index 00000000..7a566f2d
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/config/WebMvcConfig.java
@@ -0,0 +1,157 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.config;
+
+import com.cn.xiaonuo.core.web.XiaoNuoRequestResponseBodyMethodProcessor;
+import com.cn.xiaonuo.sys.core.error.XiaoNuoErrorAttributes;
+import com.cn.xiaonuo.sys.core.filter.RequestNoFilter;
+import com.cn.xiaonuo.sys.core.filter.xss.XssFilter;
+import com.cn.xiaonuo.sys.core.validator.XiaoNuoValidator;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * web配置
+ *
+ * @author yubaoshan
+ * @date 2020/4/11 10:23
+ */
+@Configuration
+@Import({cn.hutool.extra.spring.SpringUtil.class})
+public class WebMvcConfig implements WebMvcConfigurer {
+
+ /**
+ * 错误信息提示重写
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 22:27
+ */
+ @Bean
+ public XiaoNuoErrorAttributes xiaoNuoErrorAttributes() {
+ return new XiaoNuoErrorAttributes();
+ }
+
+ /**
+ * 静态资源映射
+ *
+ * @author yubaoshan
+ * @date 2020/4/11 10:23
+ */
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ //swagger增强的静态资源映射
+ registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
+ registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+ //flowable设计器静态资源映射
+ registry.addResourceHandler("/designer/**").addResourceLocations("classpath:/designer/");
+ }
+
+ /**
+ * xss过滤器
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 10:30
+ */
+ @Bean
+ public FilterRegistrationBean xssFilterFilterRegistrationBean() {
+ FilterRegistrationBean registration = new FilterRegistrationBean<>(new XssFilter());
+ registration.addUrlPatterns("/*");
+ return registration;
+ }
+
+ /**
+ * 请求唯一编号生成器
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 10:30
+ */
+ @Bean
+ public FilterRegistrationBean requestNoFilterFilterRegistrationBean() {
+ FilterRegistrationBean registration = new FilterRegistrationBean<>(new RequestNoFilter());
+ registration.addUrlPatterns("/*");
+ return registration;
+ }
+
+ /**
+ * json自定义序列化工具,long转string
+ *
+ * @author yubaoshan
+ * @date 2020/5/28 14:48
+ */
+ @Bean
+ public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
+ return jacksonObjectMapperBuilder ->
+ jacksonObjectMapperBuilder
+ .serializerByType(Long.class, ToStringSerializer.instance)
+ .serializerByType(Long.TYPE, ToStringSerializer.instance);
+ }
+
+ /**
+ * 自定义的spring参数校验器,重写主要为了保存一些在自定义validator中读不到的属性
+ *
+ * @author xuyuxiang
+ * @date 2020/8/12 20:18
+ */
+ @Bean
+ public XiaoNuoValidator xiaoNuoValidator() {
+ return new XiaoNuoValidator();
+ }
+
+
+ /**
+ * 自定义的XiaoNuoRequestResponseBodyMethodProcessor,放在所有resolvers之前
+ *
+ * @author xuyuxiang
+ * @date 2020/8/21 21:09
+ */
+ @Configuration
+ public static class MethodArgumentResolver {
+
+ @Resource
+ private RequestMappingHandlerAdapter adapter;
+
+ @PostConstruct
+ public void injectSelfMethodArgumentResolver() {
+ List argumentResolvers = new ArrayList<>();
+ argumentResolvers.add(new XiaoNuoRequestResponseBodyMethodProcessor(adapter.getMessageConverters()));
+ argumentResolvers.addAll(Objects.requireNonNull(adapter.getArgumentResolvers()));
+ adapter.setArgumentResolvers(argumentResolvers);
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/BusinessLogAop.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/BusinessLogAop.java
new file mode 100644
index 00000000..f1bedb9e
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/BusinessLogAop.java
@@ -0,0 +1,111 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.aop;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.core.log.LogManager;
+import com.alibaba.fastjson.JSON;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.annotation.Order;
+
+import java.lang.reflect.Method;
+
+/**
+ * 业务日志aop切面
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 11:47
+ */
+@Aspect
+@Order(AopSortConstant.BUSINESS_LOG_AOP)
+public class BusinessLogAop {
+
+ /**
+ * 日志切入点
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 17:10
+ */
+ @Pointcut("@annotation(com.cn.xiaonuo.core.annotion.BusinessLog)")
+ private void getLogPointCut() {
+ }
+
+ /**
+ * 操作成功返回结果记录日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 11:51
+ */
+ @AfterReturning(pointcut = "getLogPointCut()", returning = "result")
+ public void doAfterReturning(JoinPoint joinPoint, Object result) {
+ MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+ Method method = methodSignature.getMethod();
+ BusinessLog businessLog = method.getAnnotation(BusinessLog.class);
+ SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUserWithoutException();
+ String account = CommonConstant.UNKNOWN;
+ if(ObjectUtil.isNotNull(sysLoginUser)) {
+ account = sysLoginUser.getAccount();
+ }
+ //异步记录日志
+ LogManager.me().executeOperationLog(
+ businessLog, account, joinPoint, JSON.toJSONString(result));
+ }
+
+ /**
+ * 操作发生异常记录日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/21 11:38
+ */
+ @AfterThrowing(pointcut = "getLogPointCut()", throwing = "exception")
+ public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
+ MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+ Method method = methodSignature.getMethod();
+ BusinessLog businessLog = method.getAnnotation(BusinessLog.class);
+ SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUserWithoutException();
+ String account = CommonConstant.UNKNOWN;
+ if(ObjectUtil.isNotNull(sysLoginUser)) {
+ account = sysLoginUser.getAccount();
+ }
+ //异步记录日志
+ LogManager.me().executeExceptionLog(
+ businessLog, account, joinPoint, exception);
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/DataScopeAop.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/DataScopeAop.java
new file mode 100644
index 00000000..2cf9c369
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/DataScopeAop.java
@@ -0,0 +1,85 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.aop;
+
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.core.annotation.Order;
+
+import java.util.List;
+
+/**
+ * 数据权限切面
+ *
+ * @author xuyuxiang
+ * @date 2020/3/28 17:16
+ */
+@Aspect
+@Order(AopSortConstant.DATA_SCOPE_AOP)
+public class DataScopeAop {
+
+ /**
+ * 数据范围切入点
+ *
+ * @author xuyuxiang
+ * @date 2020/4/6 13:32
+ */
+ @Pointcut("@annotation(com.cn.xiaonuo.core.annotion.DataScope)")
+ private void getDataScopePointCut() {
+ }
+
+ /**
+ * 执行数据范围过滤
+ *
+ * @author xuyuxiang
+ * @date 2020/4/6 13:32
+ */
+ @Before("getDataScopePointCut()")
+ public void doDataScope(JoinPoint joinPoint) {
+
+ //不是超级管理员时进行数据权限过滤
+ if (!LoginContextHolder.me().isSuperAdmin()) {
+ Object[] args = joinPoint.getArgs();
+
+ //数据范围就是组织机构id集合
+ List loginUserDataScopeIdList = LoginContextHolder.me().getLoginUserDataScopeIdList();
+ BaseParam baseParam;
+ for (Object object : args) {
+ if (object instanceof BaseParam) {
+ baseParam = (BaseParam) object;
+ baseParam.setDataScope(loginUserDataScopeIdList);
+ }
+ }
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/PermissionAop.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/PermissionAop.java
new file mode 100644
index 00000000..a6af6275
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/PermissionAop.java
@@ -0,0 +1,138 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.aop;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.annotion.Permission;
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import com.cn.xiaonuo.core.enums.LogicTypeEnum;
+import com.cn.xiaonuo.core.exception.PermissionException;
+import com.cn.xiaonuo.core.exception.enums.PermissionExceptionEnum;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import com.cn.xiaonuo.sys.core.log.LogManager;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.annotation.Order;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+
+/**
+ * 权限过滤Aop切面
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 17:09
+ */
+@Aspect
+@Order(AopSortConstant.PERMISSION_AOP)
+public class PermissionAop {
+
+ private static final Log log = Log.get();
+
+ /**
+ * 权限切入点
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 17:10
+ */
+ @Pointcut("@annotation(com.cn.xiaonuo.core.annotion.Permission)")
+ private void getPermissionPointCut() {
+ }
+
+ /**
+ * 执行权限过滤
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 17:14
+ */
+ @Before("getPermissionPointCut()")
+ public void doPermission(JoinPoint joinPoint) {
+
+ // 如果是超级管理员,直接放过权限校验
+ boolean isSuperAdmin = LoginContextHolder.me().isSuperAdmin();
+ if (isSuperAdmin) {
+ return;
+ }
+
+ // 如果不是超级管理员,则开始进行权限校验
+ MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+ Method method = methodSignature.getMethod();
+ Permission permission = method.getAnnotation(Permission.class);
+
+ // 当前方法需要的角色集合
+ String[] requireRoles = permission.value();
+
+ // 逻辑类型
+ LogicTypeEnum logicTypeEnum = permission.logicType();
+
+ // 首先校验当前用户有没有 当前请求requestUri的权限
+ HttpServletRequest request = HttpServletUtil.getRequest();
+ boolean hasUriPermission = LoginContextHolder.me().hasPermission(request.getRequestURI());
+ if (!hasUriPermission) {
+ this.executeNoPermissionExceptionLog(joinPoint, new PermissionException(PermissionExceptionEnum.NO_PERMISSION));
+ throw new PermissionException(PermissionExceptionEnum.NO_PERMISSION);
+ }
+
+ // 如果当前接口需要特定的角色权限,则校验参数上的特殊角色当前用户有没
+ if (requireRoles.length != 0) {
+ boolean hasSpecialRolePermission = true;
+ if (LogicTypeEnum.AND.equals(logicTypeEnum)) {
+ hasSpecialRolePermission = LoginContextHolder.me().hasAllRole(StrUtil.join(SymbolConstant.COMMA, (Object) requireRoles));
+ } else if (LogicTypeEnum.OR.equals(logicTypeEnum)) {
+ hasSpecialRolePermission = LoginContextHolder.me().hasAnyRole(StrUtil.join(SymbolConstant.COMMA, (Object) requireRoles));
+ } else {
+ log.error(">>> permission注解逻辑枚举错误");
+ }
+ if (!hasSpecialRolePermission) {
+ this.executeNoPermissionExceptionLog(joinPoint, new PermissionException(PermissionExceptionEnum.NO_PERMISSION));
+ throw new PermissionException(PermissionExceptionEnum.NO_PERMISSION);
+ }
+ }
+ }
+
+ /**
+ * 记录无权限异常日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/24 11:14
+ */
+ private void executeNoPermissionExceptionLog(JoinPoint joinPoint, Exception exception) {
+ MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+ Method method = methodSignature.getMethod();
+ BusinessLog businessLog = method.getAnnotation(BusinessLog.class);
+
+ //异步记录日志
+ LogManager.me().executeExceptionLog(
+ businessLog, LoginContextHolder.me().getSysLoginUserAccount(), joinPoint, exception);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/WrapperAop.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/WrapperAop.java
new file mode 100644
index 00000000..704879e6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/aop/WrapperAop.java
@@ -0,0 +1,248 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.aop;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.annotion.Wrapper;
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.WrapperExceptionEnum;
+import com.cn.xiaonuo.core.pojo.base.wrapper.BaseWrapper;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.core.pojo.response.ResponseData;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cn.xiaonuo.core.annotion.Wrapper;
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.WrapperExceptionEnum;
+import com.cn.xiaonuo.core.pojo.base.wrapper.BaseWrapper;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.core.pojo.response.ResponseData;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.annotation.Order;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * controller结果包装的aop
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 17:42
+ */
+@Aspect
+@Order(AopSortConstant.WRAPPER_AOP)
+public class WrapperAop {
+
+ private static final Log log = Log.get();
+
+ /**
+ * 切入点
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 17:42
+ */
+ @Pointcut("@annotation(com.cn.xiaonuo.core.annotion.Wrapper)")
+ private void wrapperPointcut() {
+ }
+
+ /**
+ * 执行具体的包装过程
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 17:44
+ */
+ @Around("wrapperPointcut()")
+ public Object doWrapper(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
+
+ // 直接执行原有业务逻辑
+ Object proceedResult = proceedingJoinPoint.proceed();
+
+ return processWrapping(proceedingJoinPoint, proceedResult);
+ }
+
+ /**
+ * 具体包装过程
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 17:53
+ */
+ @SuppressWarnings("all")
+ private Object processWrapping(ProceedingJoinPoint proceedingJoinPoint, Object originResult) throws IllegalAccessException, InstantiationException {
+
+ // 获取@Wrapper注解
+ MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
+ Method method = methodSignature.getMethod();
+ Wrapper wrapperAnnotation = method.getAnnotation(Wrapper.class);
+
+ // 获取注解上的处理类
+ Class extends BaseWrapper>>[] baseWrapperClasses = wrapperAnnotation.value();
+
+ // 如果注解上的为空直接返回
+ if (ObjectUtil.isEmpty(baseWrapperClasses)) {
+ return originResult;
+ }
+
+ // 获取原有返回结果,如果不是ResponseData则不进行处理(需要遵守这个约定)
+ if (!(originResult instanceof ResponseData)) {
+ log.warn(">>> 当前请求的返回结果不是ResponseData类型,直接返回原值!");
+ return originResult;
+ }
+
+ // 获取ResponseData中的值
+ ResponseData responseData = (ResponseData) originResult;
+ Object beWrapped = responseData.getData();
+
+ // 如果是基本类型,不进行加工处理
+ if (ObjectUtil.isBasicType(beWrapped)) {
+ throw new ServiceException(WrapperExceptionEnum.BASIC_TYPE_ERROR);
+ }
+
+ // 如果是Page类型
+ if (beWrapped instanceof Page) {
+
+ // 获取Page原有对象
+ Page page = (Page) beWrapped;
+
+ // 将page中所有records都包装一遍
+ ArrayList> maps = new ArrayList<>();
+ for (Object wrappedItem : page.getRecords()) {
+ maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
+ }
+
+ page.setRecords(maps);
+ responseData.setData(page);
+ }
+
+ // 如果是PageResult类型
+ else if (beWrapped instanceof PageResult) {
+
+ // 获取PageResult原有对象
+ PageResult pageResult = (PageResult) beWrapped;
+
+ // 将PageResult中所有rows都包装一遍
+ ArrayList> maps = new ArrayList<>();
+ for (Object wrappedItem : pageResult.getRows()) {
+ maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
+ }
+
+ pageResult.setRows(maps);
+ responseData.setData(pageResult);
+ }
+
+ // 如果是List类型
+ else if (beWrapped instanceof Collection) {
+
+ // 获取原有的List
+ Collection collection = (Collection) beWrapped;
+
+ // 将page中所有records都包装一遍
+ ArrayList> maps = new ArrayList<>();
+ for (Object wrappedItem : collection) {
+ maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
+ }
+
+ responseData.setData(maps);
+ }
+
+ // 如果是Array类型
+ else if (ArrayUtil.isArray(beWrapped)) {
+
+ // 获取原有的Array
+ Object[] objects = this.objToArray(beWrapped);
+
+ // 将array中所有records都包装一遍
+ ArrayList> maps = new ArrayList<>();
+ for (Object wrappedItem : objects) {
+ maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
+ }
+
+ responseData.setData(maps);
+ }
+
+ // 如果是Object类型
+ else {
+ responseData.setData(this.wrapPureObject(beWrapped, baseWrapperClasses));
+ }
+
+
+ return responseData;
+ }
+
+ /**
+ * 原始对象包装成一个map的过程
+ *
+ * 期间多次根据BaseWrapper接口方法执行包装过程
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 21:40
+ */
+ @SuppressWarnings("all")
+ private Map wrapPureObject(Object originModel, Class extends BaseWrapper>>[] baseWrapperClasses) {
+
+ // 首先将原始的对象转化为map
+ Map originMap = BeanUtil.beanToMap(originModel);
+
+ // 经过多个包装类填充属性
+ try {
+ for (Class extends BaseWrapper>> baseWrapperClass : baseWrapperClasses) {
+ BaseWrapper baseWrapper = baseWrapperClass.newInstance();
+ Map incrementFieldsMap = baseWrapper.doWrap(originModel);
+ originMap.putAll(incrementFieldsMap);
+ }
+ } catch (Exception e) {
+ log.error(">>> 原始对象包装过程,字段转化异常:{}", e.getMessage());
+ throw new ServiceException(WrapperExceptionEnum.TRANSFER_ERROR);
+ }
+
+ return originMap;
+ }
+
+ /**
+ * Object转为一个array,确保object为数组类型
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 22:06
+ */
+ private Object[] objToArray(Object object) {
+ int length = Array.getLength(object);
+ Object[] result = new Object[length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = Array.get(object, i);
+ }
+ return result;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/MappingCache.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/MappingCache.java
new file mode 100644
index 00000000..1d0b1f16
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/MappingCache.java
@@ -0,0 +1,65 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.cache;
+
+import cn.hutool.cache.impl.TimedCache;
+import com.cn.xiaonuo.sys.core.cache.base.AbstractMemoryCacheOperator;
+
+import java.util.Map;
+
+/**
+ * mapping是映射,指业务id和业务名称的映射,或字典code和字典值的映射
+ *
+ * mapping的含义:
+ * 指对接口响应字段转化(或完善)过程
+ *
+ * 为什么要映射:
+ * 一般在查询类的方法,响应结果如果需要返回详细的一些名称信息
+ * 则需要通过left join关联对应明细表或字典表,通过id或者code查到对应的中文名称,这样做效率不高
+ *
+ * 结论:
+ * 利用缓存,将常用的字典或者业务id映射,保存起来
+ * 一方面保证了查询速度,一方面简化了代码开发,不用写一些left join之类的sql
+ *
+ * @author xuyuxiang
+ * @date 2020/7/24 11:59
+ */
+public class MappingCache extends AbstractMemoryCacheOperator> {
+
+ /**
+ * 缓存的前缀标识
+ */
+ public static final String TRANSLATES_CACHE_PREFIX = "MAPPINGS_";
+
+ public MappingCache(TimedCache> timedCache) {
+ super(timedCache);
+ }
+
+ @Override
+ public String getCommonKeyPrefix() {
+ return TRANSLATES_CACHE_PREFIX;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/OauthCache.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/OauthCache.java
new file mode 100644
index 00000000..e3f0ce82
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/OauthCache.java
@@ -0,0 +1,72 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.cache;
+
+import cn.hutool.cache.impl.CacheObj;
+import cn.hutool.cache.impl.TimedCache;
+import me.zhyd.oauth.cache.AuthCacheConfig;
+import me.zhyd.oauth.cache.AuthStateCache;
+import org.springframework.stereotype.Component;
+
+import java.util.Iterator;
+
+/**
+ * Oauth登录的缓存
+ *
+ * @author xuyuxiang
+ * @date 2020/7/28 17:42
+ **/
+@Component
+public class OauthCache implements AuthStateCache {
+
+ private final TimedCache timedCache = new TimedCache<>(AuthCacheConfig.timeout);
+
+ @Override
+ public void cache(String key, String value) {
+ timedCache.put(key, value, AuthCacheConfig.timeout);
+ }
+
+ @Override
+ public void cache(String key, String value, long timeoutSeconds) {
+ timedCache.put(key, value, AuthCacheConfig.timeout);
+ }
+
+ @Override
+ public String get(String key) {
+ return timedCache.get(key);
+ }
+
+ @Override
+ public boolean containsKey(String key) {
+ Iterator> cacheObjIterator = timedCache.cacheObjIterator();
+ while (cacheObjIterator.hasNext()) {
+ String temKey = cacheObjIterator.next().getKey();
+ if (temKey.equals(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/ResourceCache.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/ResourceCache.java
new file mode 100644
index 00000000..e8d4c1e6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/ResourceCache.java
@@ -0,0 +1,63 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.cache;
+
+import cn.hutool.core.collection.CollectionUtil;
+
+import java.util.Set;
+
+/**
+ * 项目资源的缓存,存储了项目所有的访问url
+ *
+ * 一般用在过滤器检测请求是否是项目没有的url
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 11:03
+ */
+public class ResourceCache {
+
+ private final Set resourceCaches = CollectionUtil.newHashSet();
+
+ /**
+ * 获取所有缓存资源
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 13:52
+ */
+ public Set getAllResources() {
+ return resourceCaches;
+ }
+
+ /**
+ * 直接缓存所有资源
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 13:52
+ */
+ public void putAllResources(Set resources) {
+ resourceCaches.addAll(resources);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/UserCache.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/UserCache.java
new file mode 100644
index 00000000..82016446
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/UserCache.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.cache;
+
+import cn.hutool.cache.impl.TimedCache;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.core.cache.base.AbstractMemoryCacheOperator;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+
+/**
+ * 登录用户的缓存,存储了当前登录的用户
+ *
+ * 一般用于在线用户的查看和过滤器检测用户是否登录
+ *
+ * key为用户的唯一id,value为LoginUser对象
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 11:02
+ */
+public class UserCache extends AbstractMemoryCacheOperator {
+
+ /**
+ * 登录用户缓存前缀
+ */
+ public static final String LOGIN_USER_CACHE_PREFIX = "LOGIN_USER_";
+
+ public UserCache(TimedCache timedCache) {
+ super(timedCache);
+ }
+
+ @Override
+ public String getCommonKeyPrefix() {
+ return LOGIN_USER_CACHE_PREFIX;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/base/AbstractMemoryCacheOperator.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/base/AbstractMemoryCacheOperator.java
new file mode 100644
index 00000000..5685c1be
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/base/AbstractMemoryCacheOperator.java
@@ -0,0 +1,105 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.cache.base;
+
+import cn.hutool.cache.impl.CacheObj;
+import cn.hutool.cache.impl.TimedCache;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.cn.xiaonuo.core.cache.CacheOperator;
+
+import java.util.*;
+
+/**
+ * 基于内存的缓存封装
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 10:09
+ */
+public abstract class AbstractMemoryCacheOperator implements CacheOperator {
+
+ private final TimedCache timedCache;
+
+ public AbstractMemoryCacheOperator(TimedCache timedCache) {
+ this.timedCache = timedCache;
+ }
+
+ @Override
+ public void put(String key, T value) {
+ timedCache.put(getCommonKeyPrefix() + key, value);
+ }
+
+ @Override
+ public void put(String key, T value, Long timeoutSeconds) {
+ timedCache.put(getCommonKeyPrefix() + key, value, timeoutSeconds * 1000);
+ }
+
+ @Override
+ public T get(String key) {
+ // 如果用户在超时前调用了get(key)方法,会重头计算起始时间,false的作用就是不从头算
+ return timedCache.get(getCommonKeyPrefix() + key, true);
+ }
+
+ @Override
+ public void remove(String... key) {
+ if (key.length > 0) {
+ for (String itemKey : key) {
+ timedCache.remove(getCommonKeyPrefix() + itemKey);
+ }
+ }
+ }
+
+ @Override
+ public Collection getAllKeys() {
+ Iterator> cacheObjIterator = timedCache.cacheObjIterator();
+ ArrayList keys = CollectionUtil.newArrayList();
+ while (cacheObjIterator.hasNext()) {
+ // 去掉缓存key的common prefix前缀
+ String key = cacheObjIterator.next().getKey();
+ keys.add(StrUtil.removePrefix(key, getCommonKeyPrefix()));
+ }
+ return keys;
+ }
+
+ @Override
+ public Collection getAllValues() {
+ Iterator> cacheObjIterator = timedCache.cacheObjIterator();
+ ArrayList values = CollectionUtil.newArrayList();
+ while (cacheObjIterator.hasNext()) {
+ values.add(cacheObjIterator.next().getValue());
+ }
+ return values;
+ }
+
+ @Override
+ public Map getAllKeyValues() {
+ Collection allKeys = this.getAllKeys();
+ HashMap results = CollectionUtil.newHashMap();
+ for (String key : allKeys) {
+ results.put(key, this.get(key));
+ }
+ return results;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/base/AbstractRedisCacheOperator.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/base/AbstractRedisCacheOperator.java
new file mode 100644
index 00000000..50cc19a1
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/cache/base/AbstractRedisCacheOperator.java
@@ -0,0 +1,106 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.cache.base;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.cn.xiaonuo.core.cache.CacheOperator;
+import com.cn.xiaonuo.core.cache.CacheOperator;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static com.cn.xiaonuo.core.consts.SymbolConstant.ASTERISK;
+
+/**
+ * 基于redis的缓存封装
+ *
+ * @author yubaoshan
+ * @date 2020/7/9 10:09
+ */
+public abstract class AbstractRedisCacheOperator implements CacheOperator {
+
+ private final RedisTemplate redisTemplate;
+
+ public AbstractRedisCacheOperator(RedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ @Override
+ public void put(String key, T value) {
+ redisTemplate.boundValueOps(getCommonKeyPrefix() + key).set(value);
+ }
+
+ @Override
+ public void put(String key, T value, Long timeoutSeconds) {
+ redisTemplate.boundValueOps(getCommonKeyPrefix() + key).set(value, timeoutSeconds, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public T get(String key) {
+ return redisTemplate.boundValueOps(getCommonKeyPrefix() + key).get();
+ }
+
+ @Override
+ public void remove(String... key) {
+ ArrayList keys = CollectionUtil.toList(key);
+ List withPrefixKeys = keys.stream().map(i -> getCommonKeyPrefix() + i).collect(Collectors.toList());
+ redisTemplate.delete(withPrefixKeys);
+ }
+
+ @Override
+ public Collection getAllKeys() {
+ Set keys = redisTemplate.keys(getCommonKeyPrefix() + SymbolConstant.ASTERISK);
+ if (keys != null) {
+ // 去掉缓存key的common prefix前缀
+ return keys.stream().map(key -> StrUtil.removePrefix(key, getCommonKeyPrefix())).collect(Collectors.toSet());
+ } else {
+ return CollectionUtil.newHashSet();
+ }
+ }
+
+ @Override
+ public Collection getAllValues() {
+ Set keys = redisTemplate.keys(getCommonKeyPrefix() + SymbolConstant.ASTERISK);
+ if (keys != null) {
+ return redisTemplate.opsForValue().multiGet(keys);
+ } else {
+ return CollectionUtil.newArrayList();
+ }
+ }
+
+ @Override
+ public Map getAllKeyValues() {
+ Collection allKeys = this.getAllKeys();
+ HashMap results = CollectionUtil.newHashMap();
+ for (String key : allKeys) {
+ results.put(key, this.get(key));
+ }
+ return results;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/consts/SysExpEnumConstant.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/consts/SysExpEnumConstant.java
new file mode 100644
index 00000000..9cf22d3c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/consts/SysExpEnumConstant.java
@@ -0,0 +1,124 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.consts;
+
+/**
+ * 系统管理异常枚举编码构成常量
+ *
+ * 异常枚举编码由3部分组成,如下:
+ *
+ * 模块编码(2位) + 分类编码(4位) + 具体项编码(至少1位)
+ *
+ * 模块编码和分类编码在ExpEnumCodeConstant类中声明
+ *
+ * @author yubaoshan
+ * @date 2020/6/19 20:46
+ */
+public interface SysExpEnumConstant {
+
+ /**
+ * 模块分类编码(2位)
+ *
+ * xiaonuo-system模块异常枚举编码
+ */
+ int XIAONUO_SYS_MODULE_EXP_CODE = 20;
+
+ /* 分类编码(4位) */
+ /**
+ * 系统应用相关异常枚举
+ */
+ int SYS_APP_EXCEPTION_ENUM = 1100;
+
+ /**
+ * 系统参数配置相关异常枚举
+ */
+ int SYS_CONFIG_EXCEPTION_ENUM = 1200;
+
+ /**
+ * 系统字典值相关异常枚举
+ */
+ int SYS_DICT_DATA_EXCEPTION_ENUM = 1300;
+
+ /**
+ * 系统字典类型相关异常枚举
+ */
+ int SYS_DICT_TYPE_EXCEPTION_ENUM = 1400;
+
+ /**
+ * 文件信息表相关枚举
+ */
+ int SYS_FILE_INFO_EXCEPTION_ENUM = 1500;
+
+ /**
+ * 系统菜单相关异常枚举
+ */
+ int SYS_MENU_EXCEPTION_ENUM = 1600;
+
+ /**
+ * 系统组织机构相关异常枚举
+ */
+ int SYS_ORG_EXCEPTION_ENUM = 1700;
+
+ /**
+ * 系统职位相关异常枚举
+ */
+ int SYS_POS_EXCEPTION_ENUM = 1800;
+
+ /**
+ * 系统角色相关异常枚举
+ */
+ int SYS_ROLE_EXCEPTION_ENUM = 1900;
+
+ /**
+ * 系统用户相关异常枚举
+ */
+ int SYS_USER_EXCEPTION_ENUM = 2000;
+
+ /**
+ * 系统通知公告相关异常枚举
+ */
+ int SYS_NOTICE_EXCEPTION_ENUM = 2100;
+
+ /**
+ * 定时任务相关
+ */
+ int TIMER_EXCEPTION_ENUM = 2200;
+
+ /**
+ * 邮件相关
+ */
+ int EMAIL_EXCEPTION_ENUM = 2300;
+
+ /**
+ * 短信相关
+ */
+ int SMS_EXCEPTION_ENUM = 2400;
+
+ /**
+ * Oauth登录相关
+ */
+ int OAUTH_EXCEPTION_ENUM = 2500;
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/context/SystemContextImpl.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/context/SystemContextImpl.java
new file mode 100644
index 00000000..c3a1a416
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/context/SystemContextImpl.java
@@ -0,0 +1,229 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.context;
+
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.context.system.SystemContext;
+import com.cn.xiaonuo.core.pojo.base.validate.UniqueValidateParam;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.modular.auth.service.AuthService;
+import com.cn.xiaonuo.sys.modular.dict.service.SysDictDataService;
+import com.cn.xiaonuo.sys.modular.role.entity.SysRole;
+import com.cn.xiaonuo.sys.modular.role.param.SysRoleParam;
+import com.cn.xiaonuo.sys.modular.role.service.SysRoleService;
+import com.cn.xiaonuo.sys.modular.user.entity.SysUser;
+import com.cn.xiaonuo.sys.modular.user.param.SysUserParam;
+import com.cn.xiaonuo.sys.modular.user.service.SysUserService;
+import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
+import com.cn.xiaonuo.core.context.system.SystemContext;
+import com.cn.xiaonuo.core.pojo.base.validate.UniqueValidateParam;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.modular.auth.service.AuthService;
+import com.cn.xiaonuo.sys.modular.dict.service.SysDictDataService;
+import com.cn.xiaonuo.sys.modular.role.entity.SysRole;
+import com.cn.xiaonuo.sys.modular.role.param.SysRoleParam;
+import com.cn.xiaonuo.sys.modular.role.service.SysRoleService;
+import com.cn.xiaonuo.sys.modular.user.entity.SysUser;
+import com.cn.xiaonuo.sys.modular.user.param.SysUserParam;
+import com.cn.xiaonuo.sys.modular.user.service.SysUserService;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 系统相关上下文接口实现类
+ *
+ * @author xuyuxiang
+ * @date 2020/5/6 14:59
+ */
+@Component
+public class SystemContextImpl implements SystemContext {
+
+ Log log = Log.get();
+
+ @Resource
+ private AuthService authService;
+
+ @Resource
+ private SysUserService sysUserService;
+
+ @Resource
+ private SysRoleService sysRoleService;
+
+ @Resource
+ private SysDictDataService sysDictDataService;
+
+ @Override
+ public String getNameByUserId(Long userId) {
+ return sysUserService.getNameByUserId(userId);
+ }
+
+ @Override
+ public String getNameByRoleId(Long roleId) {
+ return sysRoleService.getNameByRoleId(roleId);
+ }
+
+ @Override
+ public SysLoginUser getLoginUserByToken(String token) {
+ return authService.getLoginUserByToken(token);
+ }
+
+ @Override
+ public List listUser(String account) {
+ SysUserParam sysUserParam = new SysUserParam();
+ if (ObjectUtil.isNotEmpty(account)) {
+ sysUserParam.setAccount(account);
+ }
+ return sysUserService.list(sysUserParam);
+ }
+
+ @Override
+ public List listRole(String name) {
+ SysRoleParam sysRoleParam = new SysRoleParam();
+ if (ObjectUtil.isNotEmpty(name)) {
+ sysRoleParam.setName(name);
+ }
+ return sysRoleService.list(sysRoleParam);
+ }
+
+ @Override
+ public boolean isUser(Long userOrRoleId) {
+ SysUser sysUser = sysUserService.getById(userOrRoleId);
+ return !ObjectUtil.isNull(sysUser);
+ }
+
+ @Override
+ public boolean isRole(Long userOrRoleId) {
+ SysRole sysRole = sysRoleService.getById(userOrRoleId);
+ return !ObjectUtil.isNull(sysRole);
+ }
+
+ @Override
+ public List getDictCodesByDictTypeCode(String... dictTypeCodes) {
+ return sysDictDataService.getDictCodesByDictTypeCode(dictTypeCodes);
+ }
+
+ @Override
+ public boolean tableUniValueFlag(UniqueValidateParam uniqueValidateParam) {
+ int resultCount = 0;
+
+ // 参数校验
+ paramValidate(uniqueValidateParam);
+
+ // 不排除当前记录,不排除逻辑删除的内容
+ if (!uniqueValidateParam.getExcludeCurrentRecord()
+ && !uniqueValidateParam.getExcludeLogicDeleteItems()) {
+ resultCount = SqlRunner.db().selectCount(
+ "select count(*) from " + uniqueValidateParam.getTableName() + " where " + uniqueValidateParam.getColumnName() + " = {0}",
+ uniqueValidateParam.getValue());
+ }
+
+ // 不排除当前记录,排除逻辑删除的内容
+ if (!uniqueValidateParam.getExcludeCurrentRecord()
+ && uniqueValidateParam.getExcludeLogicDeleteItems()) {
+ resultCount = SqlRunner.db().selectCount(
+ "select count(*) from " + uniqueValidateParam.getTableName()
+ + " where " + uniqueValidateParam.getColumnName() + " = {0} "
+ + " and "
+ + "(" + uniqueValidateParam.getLogicDeleteFieldName() + " is null || "
+ + uniqueValidateParam.getLogicDeleteFieldName() + " <> " + uniqueValidateParam.getLogicDeleteValue() + ")",
+ uniqueValidateParam.getValue());
+ }
+
+ // 排除当前记录,不排除逻辑删除的内容
+ if (uniqueValidateParam.getExcludeCurrentRecord()
+ && !uniqueValidateParam.getExcludeLogicDeleteItems()) {
+
+ // id判空
+ paramIdValidate(uniqueValidateParam);
+
+ resultCount = SqlRunner.db().selectCount(
+ "select count(*) from " + uniqueValidateParam.getTableName()
+ + " where " + uniqueValidateParam.getColumnName() + " = {0} "
+ + " and id <> {1}",
+ uniqueValidateParam.getValue(), uniqueValidateParam.getId());
+ }
+
+ // 排除当前记录,排除逻辑删除的内容
+ if (uniqueValidateParam.getExcludeCurrentRecord()
+ && uniqueValidateParam.getExcludeLogicDeleteItems()) {
+
+ // id判空
+ paramIdValidate(uniqueValidateParam);
+
+ resultCount = SqlRunner.db().selectCount(
+ "select count(*) from " + uniqueValidateParam.getTableName()
+ + " where " + uniqueValidateParam.getColumnName() + " = {0} "
+ + " and id <> {1} "
+ + " and "
+ + "(" + uniqueValidateParam.getLogicDeleteFieldName() + " is null || "
+ + uniqueValidateParam.getLogicDeleteFieldName() + " <> " + uniqueValidateParam.getLogicDeleteValue() + ")",
+ uniqueValidateParam.getValue(), uniqueValidateParam.getId());
+ }
+
+ // 如果大于0,代表不是唯一的当前校验的值
+ return resultCount <= 0;
+ }
+
+ @Override
+ public List getAllUserIdList() {
+ return sysUserService.getAllUserIdList();
+ }
+
+ /**
+ * 几个参数的为空校验
+ *
+ * @author xuyuxiang
+ * @date 2020/8/17 22:00
+ */
+ private void paramValidate(UniqueValidateParam uniqueValidateParam) {
+ if (StrUtil.isBlank(uniqueValidateParam.getTableName())) {
+ throw new IllegalArgumentException("当前table字段值唯一性校验失败,tableName为空");
+ }
+ if (StrUtil.isBlank(uniqueValidateParam.getColumnName())) {
+ throw new IllegalArgumentException("当前table字段值唯一性校验失败,columnName为空");
+ }
+ if (StrUtil.isBlank(uniqueValidateParam.getValue())) {
+ throw new IllegalArgumentException("当前table字段值唯一性校验失败,字段值value为空");
+ }
+ }
+
+ /**
+ * id参数的为空校验
+ *
+ * @author xuyuxiang
+ * @date 2020/8/17 22:00
+ */
+ private void paramIdValidate(UniqueValidateParam uniqueValidateParam) {
+ if (uniqueValidateParam.getId() == null) {
+ throw new IllegalArgumentException("当前table字段值唯一性校验失败,id为空");
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/AdminTypeEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/AdminTypeEnum.java
new file mode 100644
index 00000000..c5541f04
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/AdminTypeEnum.java
@@ -0,0 +1,56 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 管理员类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 10:23
+ */
+@Getter
+public enum AdminTypeEnum {
+
+ /**
+ * 超级管理员
+ */
+ SUPER_ADMIN(1, "超级管理员"),
+
+ /**
+ * 非管理员
+ */
+ NONE(2, "非管理员");
+
+ private final Integer code;
+
+ private final String message;
+
+ AdminTypeEnum(int code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/DataScopeTypeEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/DataScopeTypeEnum.java
new file mode 100644
index 00000000..34f0921a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/DataScopeTypeEnum.java
@@ -0,0 +1,71 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 数据范围类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/5/28 11:02
+ */
+@Getter
+public enum DataScopeTypeEnum {
+
+ /**
+ * 全部数据
+ */
+ ALL(1, "全部数据"),
+
+ /**
+ * 本部门及以下数据
+ */
+ DEPT_WITH_CHILD(2, "本部门及以下数据"),
+
+ /**
+ * 本部门数据
+ */
+ DEPT(3, "本部门数据"),
+
+ /**
+ * 仅本人数据
+ */
+ SELF(4, "仅本人数据"),
+
+ /**
+ * 仅本人数据
+ */
+ DEFINE(5, "自定义数据");
+
+ private final Integer code;
+
+ private final String message;
+
+ DataScopeTypeEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/LogSuccessStatusEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/LogSuccessStatusEnum.java
new file mode 100644
index 00000000..9da88ef2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/LogSuccessStatusEnum.java
@@ -0,0 +1,56 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 日志成功状态
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 15:53
+ */
+@Getter
+public enum LogSuccessStatusEnum {
+
+ /**
+ * 失败
+ */
+ FAIL("N", "失败"),
+
+ /**
+ * 成功
+ */
+ SUCCESS("Y", "成功");
+
+ private final String code;
+
+ private final String message;
+
+ LogSuccessStatusEnum(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuOpenTypeEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuOpenTypeEnum.java
new file mode 100644
index 00000000..b346ef7f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuOpenTypeEnum.java
@@ -0,0 +1,66 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 菜单类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/5/25 15:18
+ */
+@Getter
+public enum MenuOpenTypeEnum {
+
+ /**
+ * 无
+ */
+ NONE(0, "无"),
+
+ /**
+ * 组件
+ */
+ COMPONENT(1, "组件"),
+
+ /**
+ * 内链
+ */
+ INNER(2, "内链"),
+
+ /**
+ * 外链
+ */
+ OUTER(3, "外链");
+
+ private final Integer code;
+
+ private final String message;
+
+ MenuOpenTypeEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuTypeEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuTypeEnum.java
new file mode 100644
index 00000000..d74dae9f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuTypeEnum.java
@@ -0,0 +1,61 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 菜单类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/5/25 15:18
+ */
+@Getter
+public enum MenuTypeEnum {
+
+ /**
+ * 目录
+ */
+ DIR(0, "目录"),
+
+ /**
+ * 菜单
+ */
+ MENU(1, "菜单"),
+
+ /**
+ * 按钮
+ */
+ BTN(2, "按钮");
+
+ private final Integer code;
+
+ private final String message;
+
+ MenuTypeEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuWeightEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuWeightEnum.java
new file mode 100644
index 00000000..b5c3f6b3
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/MenuWeightEnum.java
@@ -0,0 +1,56 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 菜单权重枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/5/27 17:07
+ */
+@Getter
+public enum MenuWeightEnum {
+
+ /**
+ * 系统权重
+ */
+ SUPER_ADMIN_WEIGHT(1, "系统权重"),
+
+ /**
+ * 业务权重
+ */
+ DEFAULT_WEIGHT(2, "业务权重");
+
+ private final Integer code;
+
+ private final String name;
+
+ MenuWeightEnum(Integer code, String name) {
+ this.code = code;
+ this.name = name;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/NoticeStatusEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/NoticeStatusEnum.java
new file mode 100644
index 00000000..d4880461
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/NoticeStatusEnum.java
@@ -0,0 +1,67 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 通知公告状态
+ *
+ * @author xuyuxiang
+ * @date 2020/6/28 17:51
+ */
+@Getter
+public enum NoticeStatusEnum {
+
+ /**
+ * 草稿
+ */
+ DRAFT(0, "草稿"),
+
+ /**
+ * 发布
+ */
+ PUBLIC(1, "发布"),
+
+ /**
+ * 撤回
+ */
+ CANCEL(2, "撤回"),
+
+ /**
+ * 删除
+ */
+ DELETED(3, "删除");
+
+ private final Integer code;
+
+ private final String message;
+
+ NoticeStatusEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/NoticeUserStatusEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/NoticeUserStatusEnum.java
new file mode 100644
index 00000000..1ab017f3
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/NoticeUserStatusEnum.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 通知公告用户状态
+ *
+ * @author xuyuxiang
+ * @date 2020/6/29 11:02
+ */
+@Getter
+public enum NoticeUserStatusEnum {
+
+ /**
+ * 未读
+ */
+ UNREAD(0, "未读"),
+
+ /**
+ * 已读
+ */
+ READ(1, "已读");
+
+ private final Integer code;
+
+ private final String message;
+
+ NoticeUserStatusEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/OauthPlatformEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/OauthPlatformEnum.java
new file mode 100644
index 00000000..4565ed70
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/OauthPlatformEnum.java
@@ -0,0 +1,57 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * Oauth登录授权平台的枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/7/28 16:46
+ **/
+@Getter
+public enum OauthPlatformEnum {
+
+ /**
+ * 码云
+ */
+ GITEE("gitee", "码云"),
+
+ /**
+ * github
+ */
+ GITHUB("github", "github");
+
+ private final String code;
+
+ private final String message;
+
+ OauthPlatformEnum(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/OauthSexEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/OauthSexEnum.java
new file mode 100644
index 00000000..95cf6296
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/OauthSexEnum.java
@@ -0,0 +1,61 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * Oauth用户性别枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/7/29 10:32
+ **/
+@Getter
+public enum OauthSexEnum {
+
+ /**
+ * 男
+ */
+ MAN("1", "男"),
+
+ /**
+ * 女
+ */
+ WOMAN("0", "女"),
+
+ /**
+ * 未知
+ */
+ NONE("-1", "未知");
+
+ private final String code;
+
+ private final String message;
+
+ OauthSexEnum(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/SexEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/SexEnum.java
new file mode 100644
index 00000000..c239fe54
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/SexEnum.java
@@ -0,0 +1,61 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 性别枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/5/28 10:51
+ */
+@Getter
+public enum SexEnum {
+
+ /**
+ * 男
+ */
+ MAN(1, "男"),
+
+ /**
+ * 女
+ */
+ WOMAN(2, "女"),
+
+ /**
+ * 未知
+ */
+ NONE(3, "未知");
+
+ private final Integer code;
+
+ private final String message;
+
+ SexEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/VisLogTypeEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/VisLogTypeEnum.java
new file mode 100644
index 00000000..e355b63a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/enums/VisLogTypeEnum.java
@@ -0,0 +1,56 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 访问日志类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 15:50
+ */
+@Getter
+public enum VisLogTypeEnum {
+
+ /**
+ * 登录日志
+ */
+ LOGIN(1, "登录"),
+
+ /**
+ * 退出日志
+ */
+ EXIT(2, "登出");
+
+ private final Integer code;
+
+ private final String message;
+
+ VisLogTypeEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/error/GlobalExceptionHandler.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/error/GlobalExceptionHandler.java
new file mode 100644
index 00000000..cac96031
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/error/GlobalExceptionHandler.java
@@ -0,0 +1,370 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.error;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.consts.AopSortConstant;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.context.requestno.RequestNoContext;
+import com.cn.xiaonuo.core.exception.AuthException;
+import com.cn.xiaonuo.core.exception.DemoException;
+import com.cn.xiaonuo.core.exception.PermissionException;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.*;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.pojo.response.ErrorResponseData;
+import com.cn.xiaonuo.core.sms.modular.aliyun.exp.AliyunSmsException;
+import com.cn.xiaonuo.core.sms.modular.tencent.exp.TencentSmsException;
+import com.cn.xiaonuo.core.util.ResponseUtil;
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.mybatis.spring.MyBatisSystemException;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * 全局异常处理器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:03
+ */
+@Order(AopSortConstant.GLOBAL_EXP_HANDLER_AOP)
+@ControllerAdvice
+public class GlobalExceptionHandler {
+
+ private static final Log log = Log.get();
+
+ /**
+ * 腾讯云短信发送异常
+ *
+ * @author yubaoshan
+ * @date 2020/6/7 18:03
+ */
+ @ExceptionHandler(TencentSmsException.class)
+ @ResponseBody
+ public ErrorResponseData aliyunSmsException(TencentSmsException e) {
+ log.error(">>> 发送短信异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getErrorMessage());
+ return renderJson(500, e.getErrorMessage());
+ }
+
+ /**
+ * 阿里云短信发送异常
+ *
+ * @author yubaoshan
+ * @date 2020/6/7 18:03
+ */
+ @ExceptionHandler(AliyunSmsException.class)
+ @ResponseBody
+ public ErrorResponseData aliyunSmsException(AliyunSmsException e) {
+ log.error(">>> 发送短信异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getErrorMessage());
+ return renderJson(500, e.getErrorMessage());
+ }
+
+ /**
+ * 请求参数缺失异常
+ *
+ * @author yubaoshan
+ * @date 2020/6/7 18:03
+ */
+ @ExceptionHandler(MissingServletRequestParameterException.class)
+ @ResponseBody
+ public ErrorResponseData missParamException(MissingServletRequestParameterException e) {
+ log.error(">>> 请求参数异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ String parameterType = e.getParameterType();
+ String parameterName = e.getParameterName();
+ String message = StrUtil.format(">>> 缺少请求的参数{},类型为{}", parameterName, parameterType);
+ return renderJson(500, message);
+ }
+
+ /**
+ * 拦截参数格式传递异常
+ *
+ * @author xuyuxiang
+ * @date 2020/4/2 15:32
+ */
+ @ExceptionHandler(HttpMessageNotReadableException.class)
+ @ResponseBody
+ public ErrorResponseData httpMessageNotReadable(HttpMessageNotReadableException e) {
+ log.error(">>> 参数格式传递异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ return renderJson(RequestTypeExceptionEnum.REQUEST_JSON_ERROR);
+ }
+
+ /**
+ * 拦截不支持媒体类型异常
+ *
+ * @author xuyuxiang
+ * @date 2020/4/2 15:38
+ */
+ @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
+ @ResponseBody
+ public ErrorResponseData httpMediaTypeNotSupport(HttpMediaTypeNotSupportedException e) {
+ log.error(">>> 参数格式传递异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ return renderJson(RequestTypeExceptionEnum.REQUEST_TYPE_IS_JSON);
+ }
+
+ /**
+ * 拦截请求方法的异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:14
+ */
+ @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+ @ResponseBody
+ public ErrorResponseData methodNotSupport(HttpServletRequest request) {
+ if (ServletUtil.isPostMethod(request)) {
+ log.error(">>> 请求方法异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), RequestMethodExceptionEnum.REQUEST_METHOD_IS_GET.getMessage());
+ return renderJson(RequestMethodExceptionEnum.REQUEST_METHOD_IS_GET);
+ }
+ if (ServletUtil.isGetMethod(request)) {
+ log.error(">>> 请求方法异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), RequestMethodExceptionEnum.REQUEST_METHOD_IS_POST.getMessage());
+ return renderJson(RequestMethodExceptionEnum.REQUEST_METHOD_IS_POST);
+ }
+ return null;
+ }
+
+ /**
+ * 拦截资源找不到的运行时异常
+ *
+ * @author xuyuxiang
+ * @date 2020/4/2 15:38
+ */
+ @ExceptionHandler(NoHandlerFoundException.class)
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ @ResponseBody
+ public ErrorResponseData notFound(NoHandlerFoundException e) {
+ log.error(">>> 资源不存在异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ return renderJson(PermissionExceptionEnum.URL_NOT_EXIST);
+ }
+
+ /**
+ * 拦截参数校验错误异常,JSON传参
+ *
+ * @author xuyuxiang
+ * @date 2020/4/2 15:38
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ @ResponseBody
+ public ErrorResponseData methodArgumentNotValidException(MethodArgumentNotValidException e) {
+ String argNotValidMessage = getArgNotValidMessage(e.getBindingResult());
+ log.error(">>> 参数校验错误异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), argNotValidMessage);
+ return renderJson(ParamExceptionEnum.PARAM_ERROR.getCode(), argNotValidMessage);
+ }
+
+ /**
+ * 拦截参数校验错误异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:41
+ */
+ @ExceptionHandler(BindException.class)
+ @ResponseBody
+ public ErrorResponseData paramError(BindException e) {
+ String argNotValidMessage = getArgNotValidMessage(e.getBindingResult());
+ log.error(">>> 参数校验错误异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), argNotValidMessage);
+ return renderJson(ParamExceptionEnum.PARAM_ERROR.getCode(), argNotValidMessage);
+ }
+
+ /**
+ * 拦截认证失败异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:41
+ */
+ @ExceptionHandler(AuthException.class)
+ @ResponseBody
+ public ErrorResponseData authFail(AuthException e) {
+ log.error(">>> 认证异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ return renderJson(e.getCode(), e.getErrorMessage());
+ }
+
+ /**
+ * 拦截权限异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:41
+ */
+ @ExceptionHandler(PermissionException.class)
+ @ResponseBody
+ public ErrorResponseData noPermission(PermissionException e) {
+ log.error(">>> 权限异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ return renderJson(e.getCode(), e.getErrorMessage());
+ }
+
+ /**
+ * 拦截业务异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:41
+ */
+ @ExceptionHandler(ServiceException.class)
+ @ResponseBody
+ public ErrorResponseData businessError(ServiceException e) {
+ log.error(">>> 业务异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ return renderJson(e.getCode(), e.getErrorMessage(), e);
+ }
+
+ /**
+ * 拦截mybatis数据库操作的异常
+ *
+ * 用在demo模式,拦截DemoException
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 15:19
+ */
+ @ExceptionHandler(MyBatisSystemException.class)
+ @ResponseBody
+ public ErrorResponseData persistenceException(MyBatisSystemException e) {
+ log.error(">>> mybatis操作出现异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ Throwable cause = e.getCause();
+ if (cause instanceof PersistenceException) {
+ Throwable secondCause = cause.getCause();
+ if (secondCause instanceof DemoException) {
+ DemoException demoException = (DemoException) secondCause;
+ return ResponseUtil.responseDataError(demoException.getCode(), demoException.getErrorMessage(), e.getStackTrace()[0].toString());
+ }
+ }
+ return ResponseUtil.responseDataError(ServerExceptionEnum.SERVER_ERROR.getCode(), ServerExceptionEnum.SERVER_ERROR.getMessage(), e.getStackTrace()[0].toString());
+ }
+
+ /**
+ * 拦截未知的运行时异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:41
+ */
+ @ExceptionHandler(Throwable.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public ErrorResponseData serverError(Throwable e) {
+ log.error(">>> 服务器运行异常,请求号为:{}", RequestNoContext.get());
+ e.printStackTrace();
+ return renderJson(e);
+ }
+
+ /**
+ * 渲染异常json
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 16:22
+ */
+ private ErrorResponseData renderJson(Integer code, String message) {
+ return renderJson(code, message, null);
+ }
+
+ /**
+ * 渲染异常json
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 16:22
+ */
+ private ErrorResponseData renderJson(AbstractBaseExceptionEnum baseExceptionEnum) {
+ return renderJson(baseExceptionEnum.getCode(), baseExceptionEnum.getMessage(), null);
+ }
+
+ /**
+ * 渲染异常json
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 16:22
+ */
+ private ErrorResponseData renderJson(Throwable throwable) {
+ return renderJson(((AbstractBaseExceptionEnum) ServerExceptionEnum.SERVER_ERROR).getCode(),
+ ((AbstractBaseExceptionEnum) ServerExceptionEnum.SERVER_ERROR).getMessage(), throwable);
+ }
+
+ /**
+ * 渲染异常json
+ *
+ * 根据异常枚举和Throwable异常响应,异常信息响应堆栈第一行
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 16:22
+ */
+ private ErrorResponseData renderJson(Integer code, String message, Throwable e) {
+ if (ObjectUtil.isNotNull(e)) {
+
+ //获取所有堆栈信息
+ StackTraceElement[] stackTraceElements = e.getStackTrace();
+
+ //默认的异常类全路径为第一条异常堆栈信息的
+ String exceptionClassTotalName = stackTraceElements[0].toString();
+
+ //遍历所有堆栈信息,找到com.cn.xiaonuo开头的第一条异常信息
+ for (StackTraceElement stackTraceElement : stackTraceElements) {
+ if (stackTraceElement.toString().contains(CommonConstant.DEFAULT_PACKAGE_NAME)) {
+ exceptionClassTotalName = stackTraceElement.toString();
+ break;
+ }
+ }
+ return ResponseUtil.responseDataError(code, message, exceptionClassTotalName);
+ } else {
+ return ResponseUtil.responseDataError(code, message, null);
+ }
+ }
+
+ /**
+ * 获取请求参数不正确的提示信息
+ *
+ * 多个信息,拼接成用逗号分隔的形式
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 16:50
+ */
+ private String getArgNotValidMessage(BindingResult bindingResult) {
+ if (bindingResult == null) {
+ return "";
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+
+ //多个错误用逗号分隔
+ List allErrorInfos = bindingResult.getAllErrors();
+ for (ObjectError error : allErrorInfos) {
+ stringBuilder.append(SymbolConstant.COMMA).append(error.getDefaultMessage());
+ }
+
+ //最终把首部的逗号去掉
+ return StrUtil.removePrefix(stringBuilder.toString(), SymbolConstant.COMMA);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/error/XiaoNuoErrorAttributes.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/error/XiaoNuoErrorAttributes.java
new file mode 100644
index 00000000..f29322d3
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/error/XiaoNuoErrorAttributes.java
@@ -0,0 +1,70 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.error;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.http.HttpStatus;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.PermissionExceptionEnum;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import com.cn.xiaonuo.core.pojo.response.ErrorResponseData;
+import org.springframework.boot.web.error.ErrorAttributeOptions;
+import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
+import org.springframework.web.context.request.WebRequest;
+
+import java.util.Map;
+
+/**
+ * 将系统管理未知错误异常,输出格式重写为我们熟悉的响应格式
+ *
+ * @author yubaoshan
+ * @date 2020/4/14 22:21
+ */
+public class XiaoNuoErrorAttributes extends DefaultErrorAttributes {
+
+ @Override
+ public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions attributeOptions) {
+
+ // 1.先获取spring默认的返回内容
+ Map defaultErrorAttributes = super.getErrorAttributes(webRequest, attributeOptions);
+
+ // 2.如果返回的异常是ServiceException,则按ServiceException响应的内容进行返回
+ Throwable throwable = this.getError(webRequest);
+ if (throwable instanceof ServiceException) {
+ ServiceException serviceException = (ServiceException) throwable;
+ return BeanUtil.beanToMap(new ErrorResponseData(serviceException.getCode(), serviceException.getErrorMessage()));
+ }
+
+ // 3.如果返回的是404 http状态码
+ Integer status = (Integer) defaultErrorAttributes.get("status");
+ if (status.equals(HttpStatus.HTTP_NOT_FOUND)) {
+ return BeanUtil.beanToMap(new ErrorResponseData(PermissionExceptionEnum.URL_NOT_EXIST.getCode(), PermissionExceptionEnum.URL_NOT_EXIST.getMessage()));
+ }
+
+ // 4.无法确定的返回服务器异常
+ return BeanUtil.beanToMap(new ErrorResponseData(ServerExceptionEnum.SERVER_ERROR.getCode(), ServerExceptionEnum.SERVER_ERROR.getMessage()));
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/RequestNoFilter.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/RequestNoFilter.java
new file mode 100644
index 00000000..a7d455ae
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/RequestNoFilter.java
@@ -0,0 +1,67 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.filter;
+
+
+import com.cn.xiaonuo.core.context.requestno.RequestNoContext;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * 对请求生成唯一编码
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 10:04
+ */
+public class RequestNoFilter implements Filter {
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ try {
+ // 生成唯一请求号uuid
+ String requestNo = UUID.randomUUID().toString();
+
+ // 增加响应头的请求号
+ HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+ httpServletResponse.addHeader(CommonConstant.REQUEST_NO_HEADER_NAME, requestNo);
+
+ // 临时存储
+ RequestNoContext.set(requestNo);
+
+ // 放开请求
+ chain.doFilter(request, response);
+
+ } finally {
+ // 清除临时存储的唯一编号
+ RequestNoContext.clear();
+ }
+
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/security/JwtAuthenticationTokenFilter.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/security/JwtAuthenticationTokenFilter.java
new file mode 100644
index 00000000..7eda6f7e
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/security/JwtAuthenticationTokenFilter.java
@@ -0,0 +1,100 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.filter.security;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.context.requestno.RequestNoContext;
+import com.cn.xiaonuo.core.exception.AuthException;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.core.util.ResponseUtil;
+import com.cn.xiaonuo.sys.modular.auth.service.AuthService;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.annotation.Resource;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 这个过滤器,在所有请求之前,也在spring security filters之前
+ *
+ * 这个过滤器的作用是:接口在进业务之前,添加登录上下文(SecurityContext)
+ *
+ * 因为现在没有用session了,只能token来校验当前的登录人的身份,所以在进业务之前要给当前登录人设置登录状态
+ *
+ * @author yubaoshan,xuyuxiang
+ * @date 2020/4/11 13:02
+ */
+@Component
+public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
+
+ private static final Log log = Log.get();
+
+ @Resource
+ private AuthService authService;
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException {
+ try {
+ doFilter(request, response, filterChain);
+ } catch (Exception e) {
+ log.error(">>> 服务器运行异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ ResponseUtil.responseExceptionError(response, ServerExceptionEnum.SERVER_ERROR.getCode(),
+ ServerExceptionEnum.SERVER_ERROR.getMessage(), e.getStackTrace()[0].toString());
+ }
+ }
+
+ private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+
+ // 1.如果当前请求带了token,判断token时效性,并获取当前登录用户信息
+ SysLoginUser sysLoginUser = null;
+ try {
+ String token = authService.getTokenFromRequest(request);
+ if (StrUtil.isNotEmpty(token)) {
+ sysLoginUser = authService.getLoginUserByToken(token);
+ }
+ } catch (AuthException ae) {
+ //token过期或者token失效的情况,响应给前端
+ ResponseUtil.responseExceptionError(response, ae.getCode(), ae.getErrorMessage(), ae.getStackTrace()[0].toString());
+ return;
+ }
+
+ // 2.如果当前登录用户不为空,就设置spring security上下文
+ if (ObjectUtil.isNotNull(sysLoginUser)) {
+ authService.setSpringSecurityContextAuthentication(sysLoginUser);
+ }
+
+ // 3.其他情况放开过滤
+ filterChain.doFilter(request, response);
+
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/security/entrypoint/JwtAuthenticationEntryPoint.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/security/entrypoint/JwtAuthenticationEntryPoint.java
new file mode 100644
index 00000000..2aa684a9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/security/entrypoint/JwtAuthenticationEntryPoint.java
@@ -0,0 +1,99 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.filter.security.entrypoint;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.AuthExceptionEnum;
+import com.cn.xiaonuo.core.exception.enums.PermissionExceptionEnum;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import com.cn.xiaonuo.core.util.ResponseUtil;
+import com.cn.xiaonuo.sys.core.cache.ResourceCache;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collection;
+
+/**
+ * 未认证用户访问须授权资源端点
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 11:52
+ */
+@Component
+public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
+
+ private static final Log log = Log.get();
+
+ @Resource
+ private ResourceCache resourceCache;
+
+ /**
+ * 访问未经授权的接口时执行此方法,未经授权的接口包含系统中存在和不存在的接口,分别处理
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:15
+ */
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
+
+ String requestUri = request.getRequestURI();
+
+ //1.检查redis中RESOURCE缓存是否为空,如果为空,直接抛出系统异常,缓存url作用详见ResourceCollectListener
+ Collection urlCollections = resourceCache.getAllResources();
+ if (ObjectUtil.isEmpty(urlCollections)) {
+ log.error(">>> 获取缓存的Resource Url为空,请检查缓存中是否被误删,requestUri={}", requestUri);
+ ResponseUtil.responseExceptionError(response,
+ ServerExceptionEnum.SERVER_ERROR.getCode(),
+ ServerExceptionEnum.SERVER_ERROR.getMessage(),
+ new ServiceException(ServerExceptionEnum.SERVER_ERROR).getStackTrace()[0].toString());
+ return;
+ }
+
+ //2.判断缓存的url中是否有当前请求的uri,没有的话响应给前端404
+ if (!urlCollections.contains(requestUri)) {
+ log.error(">>> 当前请求的uri不存在,请检查请求地址是否正确或缓存中是否被误删,requestUri={}", requestUri);
+ ResponseUtil.responseExceptionError(response,
+ PermissionExceptionEnum.URL_NOT_EXIST.getCode(),
+ PermissionExceptionEnum.URL_NOT_EXIST.getMessage(),
+ new ServiceException(PermissionExceptionEnum.URL_NOT_EXIST).getStackTrace()[0].toString());
+ return;
+ }
+
+ //3.响应给前端无权限访问本接口(没有携带token)
+ log.error(">>> 没有权限访问该资源,requestUri={}", requestUri);
+ ResponseUtil.responseExceptionError(response,
+ AuthExceptionEnum.REQUEST_TOKEN_EMPTY.getCode(),
+ AuthExceptionEnum.REQUEST_TOKEN_EMPTY.getMessage(),
+ new ServiceException(AuthExceptionEnum.REQUEST_TOKEN_EMPTY).getStackTrace()[0].toString());
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/xss/XssFilter.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/xss/XssFilter.java
new file mode 100644
index 00000000..75a2cb77
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/xss/XssFilter.java
@@ -0,0 +1,58 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.filter.xss;
+
+
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * xss过滤器
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 10:04
+ */
+public class XssFilter implements Filter {
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+ String servletPath = httpServletRequest.getServletPath();
+
+ // 获取不进行url过滤的接口
+ List unXssFilterUrl = ConstantContextHolder.getUnXssFilterUrl();
+ if (unXssFilterUrl != null && unXssFilterUrl.contains(servletPath)) {
+ chain.doFilter(request, response);
+ } else {
+ chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/xss/XssHttpServletRequestWrapper.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/xss/XssHttpServletRequestWrapper.java
new file mode 100644
index 00000000..c519b173
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/filter/xss/XssHttpServletRequestWrapper.java
@@ -0,0 +1,91 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.filter.xss;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+/**
+ * xss针对http请求的包装
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 10:29
+ */
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
+
+ XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
+ super(servletRequest);
+ }
+
+ @Override
+ public String[] getParameterValues(String parameter) {
+ String[] values = super.getParameterValues(parameter);
+ if (values == null) {
+ return null;
+ }
+ int count = values.length;
+ String[] encodedValues = new String[count];
+ for (int i = 0; i < count; i++) {
+ encodedValues[i] = cleanXss(values[i]);
+ }
+ return encodedValues;
+
+ }
+
+ @Override
+ public String getParameter(String parameter) {
+ String value = super.getParameter(parameter);
+ if (value == null) {
+ return null;
+ }
+ return cleanXss(value);
+ }
+
+ @Override
+ public String getHeader(String name) {
+ String value = super.getHeader(name);
+ if (value == null) {
+ return null;
+ }
+ return cleanXss(value);
+ }
+
+ private String cleanXss(String value) {
+
+ value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
+
+ value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
+
+ value = value.replaceAll("'", "& #39;");
+
+ value = value.replaceAll("eval\\((.*)\\)", "");
+
+ value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
+
+ return value;
+
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/jwt/JwtPayLoad.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/jwt/JwtPayLoad.java
new file mode 100644
index 00000000..2763aaa1
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/jwt/JwtPayLoad.java
@@ -0,0 +1,62 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.jwt;
+
+import cn.hutool.core.util.IdUtil;
+import lombok.Data;
+
+/**
+ * JwtPayLoad部分
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 17:41
+ */
+@Data
+public class JwtPayLoad {
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 账号
+ */
+ private String account;
+
+ /**
+ * 唯一表示id, 用于缓存登录用户的唯一凭证
+ */
+ private String uuid;
+
+ public JwtPayLoad() {
+ }
+
+ public JwtPayLoad(Long userId, String account) {
+ this.userId = userId;
+ this.account = account;
+ this.uuid = IdUtil.fastUUID();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/jwt/JwtTokenUtil.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/jwt/JwtTokenUtil.java
new file mode 100644
index 00000000..736f039a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/jwt/JwtTokenUtil.java
@@ -0,0 +1,118 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.jwt;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import io.jsonwebtoken.*;
+
+import java.util.Date;
+
+/**
+ * JwtToken工具类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 17:39
+ */
+public class JwtTokenUtil {
+
+ /**
+ * 生成token
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 17:52
+ */
+ public static String generateToken(JwtPayLoad jwtPayLoad) {
+
+ DateTime expirationDate = DateUtil.offsetMillisecond(new Date(),
+ Convert.toInt(ConstantContextHolder.getTokenExpireSec()) * 1000);
+ return Jwts.builder()
+ .setClaims(BeanUtil.beanToMap(jwtPayLoad))
+ .setSubject(jwtPayLoad.getUserId().toString())
+ .setIssuedAt(new Date())
+ .setExpiration(expirationDate)
+ .signWith(SignatureAlgorithm.HS512, ConstantContextHolder.getJwtSecret())
+ .compact();
+ }
+
+ /**
+ * 根据token获取Claims
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 10:29
+ */
+ private static Claims getClaimsFromToken(String token) {
+ return Jwts.parser()
+ .setSigningKey(ConstantContextHolder.getJwtSecret())
+ .parseClaimsJws(token)
+ .getBody();
+ }
+
+ /**
+ * 获取JwtPayLoad部分
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 17:53
+ */
+ public static JwtPayLoad getJwtPayLoad(String token) {
+ Claims claims = getClaimsFromToken(token);
+ return BeanUtil.mapToBean(claims, JwtPayLoad.class, false);
+ }
+
+ /**
+ * 校验token是否正确
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 10:36
+ */
+ public static Boolean checkToken(String token) {
+ try {
+ getClaimsFromToken(token);
+ return true;
+ } catch (JwtException jwtException) {
+ return false;
+ }
+ }
+
+ /**
+ * 校验token是否失效
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 10:30
+ */
+ public static Boolean isTokenExpired(String token) {
+ try {
+ Claims claims = getClaimsFromToken(token);
+ final Date expiration = claims.getExpiration();
+ return expiration.before(new Date());
+ } catch (ExpiredJwtException expiredJwtException) {
+ return true;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/ConstantsInitListener.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/ConstantsInitListener.java
new file mode 100644
index 00000000..4fb66a3f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/ConstantsInitListener.java
@@ -0,0 +1,105 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.listener;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.db.DbUtil;
+import cn.hutool.db.Entity;
+import cn.hutool.db.handler.EntityListHandler;
+import cn.hutool.db.sql.SqlExecutor;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.context.constant.ConstantContext;
+import com.cn.xiaonuo.core.enums.CommonStatusEnum;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.sys.modular.consts.enums.SysConfigExceptionEnum;
+import com.cn.xiaonuo.core.context.constant.ConstantContext;
+import com.cn.xiaonuo.core.enums.CommonStatusEnum;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.sys.modular.consts.enums.SysConfigExceptionEnum;
+import org.springframework.boot.context.event.ApplicationContextInitializedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * 初始化常量的监听器
+ *
+ * 当spring装配好配置后,就去数据库读constants
+ *
+ * @author yubaoshan
+ * @date 2020/6/6 23:39
+ */
+public class ConstantsInitListener implements ApplicationListener, Ordered {
+
+ private static final Log log = Log.get();
+
+ private static final String CONFIG_LIST_SQL = "select code,value from sys_config where status = ?";
+
+ @Override
+ public int getOrder() {
+ return Ordered.HIGHEST_PRECEDENCE;
+ }
+
+ @Override
+ public void onApplicationEvent(ApplicationContextInitializedEvent applicationContextInitializedEvent) {
+ ConfigurableEnvironment environment = applicationContextInitializedEvent.getApplicationContext().getEnvironment();
+
+ // 获取数据库连接配置
+ String dataSourceUrl = environment.getProperty("spring.datasource.url");
+ String dataSourceUsername = environment.getProperty("spring.datasource.username");
+ String dataSourcePassword = environment.getProperty("spring.datasource.password");
+
+ // 如果有为空的配置,终止执行
+ if (ObjectUtil.hasEmpty(dataSourceUrl, dataSourceUsername, dataSourcePassword)) {
+ throw new ServiceException(SysConfigExceptionEnum.DATA_SOURCE_NOT_EXIST);
+ }
+
+ Connection conn = null;
+ try {
+ Class.forName("com.mysql.cj.jdbc.Driver");
+ assert dataSourceUrl != null;
+ conn = DriverManager.getConnection(dataSourceUrl, dataSourceUsername, dataSourcePassword);
+
+ // 获取sys_config表的数据
+ List entityList = SqlExecutor.query(conn, CONFIG_LIST_SQL, new EntityListHandler(), CommonStatusEnum.ENABLE.getCode());
+
+ // 将查询到的参数配置添加到缓存
+ if (ObjectUtil.isNotEmpty(entityList)) {
+ entityList.forEach(sysConfig -> ConstantContext.putConstant(sysConfig.getStr("code"), sysConfig.getStr("value")));
+ }
+ } catch (SQLException | ClassNotFoundException e) {
+ log.error(">>> 读取数据库constants配置信息出错:{}", e.getMessage());
+ throw new ServiceException(SysConfigExceptionEnum.DATA_SOURCE_NOT_EXIST);
+ } finally {
+ DbUtil.close(conn);
+ }
+
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/RemoveRequestParamListener.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/RemoveRequestParamListener.java
new file mode 100644
index 00000000..8d1d70f3
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/RemoveRequestParamListener.java
@@ -0,0 +1,20 @@
+package com.cn.xiaonuo.sys.core.listener;
+
+import com.cn.xiaonuo.core.context.param.RequestParamContext;
+import org.springframework.context.ApplicationListener;
+import org.springframework.web.context.support.ServletRequestHandledEvent;
+
+/**
+ * 用来清除临时缓存的@RequestBody的请求参数
+ *
+ * @author xuyuxiang
+ * @date 2020/8/21 21:14
+ */
+public class RemoveRequestParamListener implements ApplicationListener {
+
+ @Override
+ public void onApplicationEvent(ServletRequestHandledEvent event) {
+ RequestParamContext.clear();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/ResourceCollectListener.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/ResourceCollectListener.java
new file mode 100644
index 00000000..0f8cc6e6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/ResourceCollectListener.java
@@ -0,0 +1,79 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.listener;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.sys.core.cache.ResourceCache;
+import com.cn.xiaonuo.sys.core.cache.ResourceCache;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 资源搜集器,将项目中所有接口(带@RequestMapping的)都搜集起来
+ *
+ * 搜集到的接口会被缓存,用于请求时判断请求的接口是否存在
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 17:33
+ */
+@Component
+public class ResourceCollectListener implements CommandLineRunner {
+
+ private static final Log log = Log.get();
+
+ @Resource
+ private ResourceCache resourceCache;
+
+ @Override
+ public void run(String... args) {
+
+ //1.获取所有后端接口
+ Set urlSet = CollectionUtil.newHashSet();
+ Map mappingMap = SpringUtil.getApplicationContext().getBeansOfType(RequestMappingHandlerMapping.class);
+ Collection mappings = mappingMap.values();
+ for (RequestMappingHandlerMapping mapping : mappings) {
+ Map map = mapping.getHandlerMethods();
+ map.keySet().forEach(requestMappingInfo -> {
+ Set patterns = requestMappingInfo.getPatternsCondition().getPatterns();
+ urlSet.addAll(patterns);
+ });
+ }
+
+ //2.汇总添加到缓存
+ resourceCache.putAllResources(urlSet);
+
+ log.info(">>> 缓存资源URL集合完成!资源数量:{}", urlSet.size());
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/TimerTaskRunListener.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/TimerTaskRunListener.java
new file mode 100644
index 00000000..e1a2f405
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/listener/TimerTaskRunListener.java
@@ -0,0 +1,80 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.listener;
+
+import cn.hutool.cron.CronUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.cn.xiaonuo.sys.modular.timer.entity.SysTimers;
+import com.cn.xiaonuo.sys.modular.timer.enums.TimerJobStatusEnum;
+import com.cn.xiaonuo.sys.modular.timer.param.SysTimersParam;
+import com.cn.xiaonuo.sys.modular.timer.service.SysTimersService;
+import com.cn.xiaonuo.sys.modular.timer.service.TimerExeService;
+import com.cn.xiaonuo.sys.modular.timer.entity.SysTimers;
+import com.cn.xiaonuo.sys.modular.timer.enums.TimerJobStatusEnum;
+import com.cn.xiaonuo.sys.modular.timer.param.SysTimersParam;
+import com.cn.xiaonuo.sys.modular.timer.service.SysTimersService;
+import com.cn.xiaonuo.sys.modular.timer.service.TimerExeService;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.core.Ordered;
+
+import java.util.List;
+
+/**
+ * 项目定时任务启动的listener
+ *
+ * @author yubaoshan
+ * @date 2020/7/1 15:30
+ */
+public class TimerTaskRunListener implements ApplicationListener, Ordered {
+
+ @Override
+ public void onApplicationEvent(ApplicationStartedEvent event) {
+
+ SysTimersService sysTimersService = SpringUtil.getBean(SysTimersService.class);
+ TimerExeService timerExeService = SpringUtil.getBean(TimerExeService.class);
+
+ // 获取所有开启状态的任务
+ SysTimersParam sysTimersParam = new SysTimersParam();
+ sysTimersParam.setJobStatus(TimerJobStatusEnum.RUNNING.getCode());
+ List list = sysTimersService.list(sysTimersParam);
+
+ // 添加定时任务到调度器
+ for (SysTimers sysTimers : list) {
+ timerExeService.startTimer(String.valueOf(sysTimers.getId()), sysTimers.getCron(), sysTimers.getActionClass());
+ }
+
+ // 设置秒级别的启用
+ CronUtil.setMatchSecond(true);
+
+ // 启动定时器执行器
+ CronUtil.start();
+ }
+
+ @Override
+ public int getOrder() {
+ return LOWEST_PRECEDENCE;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/LogManager.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/LogManager.java
new file mode 100644
index 00000000..d2be4e83
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/LogManager.java
@@ -0,0 +1,185 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.log;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import com.cn.xiaonuo.core.util.IpAddressUtil;
+import com.cn.xiaonuo.core.util.UaUtil;
+import com.cn.xiaonuo.sys.core.log.factory.LogFactory;
+import com.cn.xiaonuo.sys.core.log.factory.LogTaskFactory;
+import com.cn.xiaonuo.sys.modular.log.entity.SysOpLog;
+import com.cn.xiaonuo.sys.modular.log.entity.SysVisLog;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import com.cn.xiaonuo.core.util.IpAddressUtil;
+import com.cn.xiaonuo.core.util.UaUtil;
+import org.aspectj.lang.JoinPoint;
+import org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * 日志管理器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 14:13
+ */
+public class LogManager {
+
+ /**
+ * 异步操作记录日志的线程池
+ */
+ private static final ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(10, new ScheduledExecutorFactoryBean());
+
+ private LogManager() {
+ }
+
+ private static final LogManager LOG_MANAGER = new LogManager();
+
+ public static LogManager me() {
+ return LOG_MANAGER;
+ }
+
+ /**
+ * 异步执行日志的方法
+ *
+ * @author xuyuxiang
+ * @date 2020/4/8 19:19
+ */
+ private void executeLog(TimerTask task) {
+
+ //如果演示模式开启,则不记录日志
+ if (ConstantContextHolder.getDemoEnvFlag()) {
+ return;
+ }
+
+ //日志记录操作延时
+ int operateDelayTime = 10;
+ EXECUTOR.schedule(task, operateDelayTime, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * 登录日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 20:00
+ */
+ public void executeLoginLog(final String account, final String success, final String failMessage) {
+ SysVisLog sysVisLog = this.genBaseSysVisLog();
+ TimerTask timerTask = LogTaskFactory.loginLog(sysVisLog, account,
+ success,
+ failMessage);
+ executeLog(timerTask);
+ }
+
+ /**
+ * 登出日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 20:01
+ */
+ public void executeExitLog(final String account) {
+ SysVisLog sysVisLog = this.genBaseSysVisLog();
+ TimerTask timerTask = LogTaskFactory.exitLog(sysVisLog, account);
+ executeLog(timerTask);
+ }
+
+ /**
+ * 操作日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 20:01
+ */
+ public void executeOperationLog(BusinessLog businessLog, final String account, JoinPoint joinPoint, final String result) {
+ SysOpLog sysOpLog = this.genBaseSysOpLog();
+ TimerTask timerTask = LogTaskFactory.operationLog(sysOpLog, account, businessLog, joinPoint, result);
+ executeLog(timerTask);
+ }
+
+ /**
+ * 异常日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 20:01
+ */
+ public void executeExceptionLog(BusinessLog businessLog, final String account, JoinPoint joinPoint, Exception exception) {
+ SysOpLog sysOpLog = this.genBaseSysOpLog();
+ TimerTask timerTask = LogTaskFactory.exceptionLog(sysOpLog, account, businessLog, joinPoint, exception);
+ executeLog(timerTask);
+ }
+
+ /**
+ * 构建基础访问日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:44
+ */
+ private SysVisLog genBaseSysVisLog() {
+ HttpServletRequest request = HttpServletUtil.getRequest();
+ if (ObjectUtil.isNotNull(request)) {
+ String ip = IpAddressUtil.getIp(request);
+ String address = IpAddressUtil.getAddress(request);
+ String browser = UaUtil.getBrowser(request);
+ String os = UaUtil.getOs(request);
+ return LogFactory.genBaseSysVisLog(ip, address, browser, os);
+ } else {
+ throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
+ }
+ }
+
+ /**
+ * 构建基础操作日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:44
+ */
+ private SysOpLog genBaseSysOpLog() {
+ HttpServletRequest request = HttpServletUtil.getRequest();
+ if (ObjectUtil.isNotNull(request)) {
+ String ip = IpAddressUtil.getIp(request);
+ String address = IpAddressUtil.getAddress(request);
+ String browser = UaUtil.getBrowser(request);
+ String os = UaUtil.getOs(request);
+ String url = request.getRequestURI();
+ String method = request.getMethod();
+ return LogFactory.genBaseSysOpLog(ip, address, browser, os, url, method);
+ } else {
+ throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/factory/LogFactory.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/factory/LogFactory.java
new file mode 100644
index 00000000..28c7527b
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/factory/LogFactory.java
@@ -0,0 +1,169 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.log.factory;
+
+import cn.hutool.core.date.DateTime;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.util.JoinPointUtil;
+import com.cn.xiaonuo.sys.core.enums.LogSuccessStatusEnum;
+import com.cn.xiaonuo.sys.core.enums.VisLogTypeEnum;
+import com.cn.xiaonuo.sys.modular.log.entity.SysOpLog;
+import com.cn.xiaonuo.sys.modular.log.entity.SysVisLog;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.util.JoinPointUtil;
+import com.cn.xiaonuo.sys.core.enums.LogSuccessStatusEnum;
+import com.cn.xiaonuo.sys.core.enums.VisLogTypeEnum;
+import org.aspectj.lang.JoinPoint;
+
+import java.util.Arrays;
+
+/**
+ * 日志对象创建工厂
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 14:31
+ */
+public class LogFactory {
+
+ /**
+ * 创建登录日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 16:09
+ */
+ static void createSysLoginLog(SysVisLog sysVisLog, String account, String successCode, String failMessage) {
+ sysVisLog.setName(VisLogTypeEnum.LOGIN.getMessage());
+ sysVisLog.setSuccess(successCode);
+
+ sysVisLog.setVisType(VisLogTypeEnum.LOGIN.getCode());
+ sysVisLog.setVisTime(DateTime.now());
+ sysVisLog.setAccount(account);
+
+ if (LogSuccessStatusEnum.SUCCESS.getCode().equals(successCode)) {
+ sysVisLog.setMessage(VisLogTypeEnum.LOGIN.getMessage() + LogSuccessStatusEnum.SUCCESS.getMessage());
+ }
+ if (LogSuccessStatusEnum.FAIL.getCode().equals(successCode)) {
+ sysVisLog.setMessage(VisLogTypeEnum.LOGIN.getMessage() +
+ LogSuccessStatusEnum.FAIL.getMessage() + SymbolConstant.COLON + failMessage);
+ }
+ }
+
+ /**
+ * 创建登出日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 16:09
+ */
+ static void createSysExitLog(SysVisLog sysVisLog, String account) {
+ sysVisLog.setName(VisLogTypeEnum.EXIT.getMessage());
+ sysVisLog.setSuccess(LogSuccessStatusEnum.SUCCESS.getCode());
+ sysVisLog.setMessage(VisLogTypeEnum.EXIT.getMessage() + LogSuccessStatusEnum.SUCCESS.getMessage());
+ sysVisLog.setVisType(VisLogTypeEnum.EXIT.getCode());
+ sysVisLog.setVisTime(DateTime.now());
+ sysVisLog.setAccount(account);
+ }
+
+ /**
+ * 创建操作日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 16:09
+ */
+ static void createSysOperationLog(SysOpLog sysOpLog, String account, BusinessLog businessLog, JoinPoint joinPoint, String result) {
+ fillCommonSysOpLog(sysOpLog, account, businessLog, joinPoint);
+ sysOpLog.setSuccess(LogSuccessStatusEnum.SUCCESS.getCode());
+ sysOpLog.setResult(result);
+ sysOpLog.setMessage(LogSuccessStatusEnum.SUCCESS.getMessage());
+ }
+
+ /**
+ * 创建异常日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 17:18
+ */
+ static void createSysExceptionLog(SysOpLog sysOpLog, String account, BusinessLog businessLog, JoinPoint joinPoint, Exception exception) {
+ fillCommonSysOpLog(sysOpLog, account, businessLog, joinPoint);
+ sysOpLog.setSuccess(LogSuccessStatusEnum.FAIL.getCode());
+ sysOpLog.setMessage(Arrays.toString(exception.getStackTrace()));
+ }
+
+ /**
+ * 生成通用操作日志字段
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 17:20
+ */
+ private static void fillCommonSysOpLog(SysOpLog sysOpLog, String account, BusinessLog businessLog, JoinPoint joinPoint) {
+ String className = joinPoint.getTarget().getClass().getName();
+
+ String methodName = joinPoint.getSignature().getName();
+
+ String param = JoinPointUtil.getArgsJsonString(joinPoint);
+
+ sysOpLog.setName(businessLog.title());
+ sysOpLog.setOpType(businessLog.opType().ordinal());
+ sysOpLog.setClassName(className);
+ sysOpLog.setMethodName(methodName);
+ sysOpLog.setParam(param);
+ sysOpLog.setOpTime(DateTime.now());
+ sysOpLog.setAccount(account);
+ }
+
+ /**
+ * 构建基础访问日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:36
+ */
+ public static SysVisLog genBaseSysVisLog(String ip, String location, String browser, String os) {
+ SysVisLog sysVisLog = new SysVisLog();
+ sysVisLog.setIp(ip);
+ sysVisLog.setLocation(location);
+ sysVisLog.setBrowser(browser);
+ sysVisLog.setOs(os);
+ return sysVisLog;
+ }
+
+ /**
+ * 构建基础操作日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/19 14:36
+ */
+ public static SysOpLog genBaseSysOpLog(String ip, String location, String browser, String os, String url, String method) {
+ SysOpLog sysOpLog = new SysOpLog();
+ sysOpLog.setIp(ip);
+ sysOpLog.setLocation(location);
+ sysOpLog.setBrowser(browser);
+ sysOpLog.setOs(os);
+ sysOpLog.setUrl(url);
+ sysOpLog.setReqMethod(method);
+ return sysOpLog;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/factory/LogTaskFactory.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/factory/LogTaskFactory.java
new file mode 100644
index 00000000..1364921f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/log/factory/LogTaskFactory.java
@@ -0,0 +1,135 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.log.factory;
+
+import cn.hutool.extra.spring.SpringUtil;
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.context.requestno.RequestNoContext;
+import com.cn.xiaonuo.sys.modular.log.entity.SysOpLog;
+import com.cn.xiaonuo.sys.modular.log.entity.SysVisLog;
+import com.cn.xiaonuo.sys.modular.log.service.SysOpLogService;
+import com.cn.xiaonuo.sys.modular.log.service.SysVisLogService;
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.context.requestno.RequestNoContext;
+import org.aspectj.lang.JoinPoint;
+
+import java.util.TimerTask;
+
+
+/**
+ * 日志操作任务创建工厂
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 14:18
+ */
+public class LogTaskFactory {
+
+ private static final Log log = Log.get();
+
+ private static final SysVisLogService sysVisLogService = SpringUtil.getBean(SysVisLogService.class);
+
+ private static final SysOpLogService sysOpLogService = SpringUtil.getBean(SysOpLogService.class);
+
+ /**
+ * 登录日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 15:21
+ */
+ public static TimerTask loginLog(SysVisLog sysVisLog, final String account, String success, String failMessage) {
+ return new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ LogFactory.createSysLoginLog(sysVisLog, account, success, failMessage);
+ sysVisLogService.save(sysVisLog);
+ } catch (Exception e) {
+ log.error(">>> 创建登录日志异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ }
+ }
+ };
+ }
+
+ /**
+ * 登出日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 15:21
+ */
+ public static TimerTask exitLog(SysVisLog sysVisLog, String account) {
+ return new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ LogFactory.createSysExitLog(sysVisLog, account);
+ sysVisLogService.save(sysVisLog);
+ } catch (Exception e) {
+ log.error(">>> 创建退出日志异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ }
+ }
+ };
+ }
+
+ /**
+ * 操作日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 15:21
+ */
+ public static TimerTask operationLog(SysOpLog sysOpLog, String account, BusinessLog businessLog, JoinPoint joinPoint, String result) {
+ return new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ LogFactory.createSysOperationLog(sysOpLog, account, businessLog, joinPoint, result);
+ sysOpLogService.save(sysOpLog);
+ } catch (Exception e) {
+ log.error(">>> 创建操作日志异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ }
+ }
+ };
+ }
+
+ /**
+ * 异常日志
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 15:21
+ */
+ public static TimerTask exceptionLog(SysOpLog sysOpLog, String account, BusinessLog businessLog, JoinPoint joinPoint, Exception exception) {
+ return new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ LogFactory.createSysExceptionLog(sysOpLog, account, businessLog, joinPoint, exception);
+ sysOpLogService.save(sysOpLog);
+ } catch (Exception e) {
+ log.error(">>> 创建异常日志异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
+ }
+ }
+ };
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/dbid/XiaoNuoDatabaseIdProvider.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/dbid/XiaoNuoDatabaseIdProvider.java
new file mode 100644
index 00000000..ed976bd9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/dbid/XiaoNuoDatabaseIdProvider.java
@@ -0,0 +1,61 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.mybatis.dbid;
+
+import com.cn.xiaonuo.core.enums.DbIdEnum;
+import com.cn.xiaonuo.core.enums.DbIdEnum;
+import org.apache.ibatis.mapping.DatabaseIdProvider;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+import java.util.Properties;
+
+/**
+ * 数据库id选择器
+ *
+ * @author yubaoshan
+ * @date 2019/3/30 22:26
+ */
+public class XiaoNuoDatabaseIdProvider implements DatabaseIdProvider {
+
+ @Override
+ public void setProperties(Properties p) {
+ }
+
+ @Override
+ public String getDatabaseId(DataSource dataSource) throws SQLException {
+ String url = dataSource.getConnection().getMetaData().getURL();
+
+ if (url.contains(DbIdEnum.ORACLE.getName())) {
+ return DbIdEnum.ORACLE.getCode();
+ } else if (url.contains(DbIdEnum.PG_SQL.getName())) {
+ return DbIdEnum.PG_SQL.getCode();
+ } else if (url.contains(DbIdEnum.MS_SQL.getName())) {
+ return DbIdEnum.MS_SQL.getCode();
+ } else {
+ return DbIdEnum.MYSQL.getCode();
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/fieldfill/CustomMetaObjectHandler.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/fieldfill/CustomMetaObjectHandler.java
new file mode 100644
index 00000000..e8775ada
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/fieldfill/CustomMetaObjectHandler.java
@@ -0,0 +1,90 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.mybatis.fieldfill;
+
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.ReflectionException;
+
+import java.util.Date;
+
+/**
+ * 自定义sql字段填充器,自动填充创建修改相关字段
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 15:21
+ */
+public class CustomMetaObjectHandler implements MetaObjectHandler {
+
+ private static final Log log = Log.get();
+
+ private static final String CREATE_USER = "createUser";
+
+ private static final String CREATE_TIME = "createTime";
+
+ private static final String UPDATE_USER = "updateUser";
+
+ private static final String UPDATE_TIME = "updateTime";
+
+ @Override
+ public void insertFill(MetaObject metaObject) {
+ try {
+ //设置createUser(BaseEntity)
+ setFieldValByName(CREATE_USER, this.getUserUniqueId(), metaObject);
+
+ //设置createTime(BaseEntity)
+ setFieldValByName(CREATE_TIME, new Date(), metaObject);
+ } catch (ReflectionException e) {
+ log.warn(">>> CustomMetaObjectHandler处理过程中无相关字段,不做处理");
+ }
+ }
+
+ @Override
+ public void updateFill(MetaObject metaObject) {
+ try {
+ //设置updateUser(BaseEntity)
+ setFieldValByName(UPDATE_USER, this.getUserUniqueId(), metaObject);
+ //设置updateTime(BaseEntity)
+ setFieldValByName(UPDATE_TIME, new Date(), metaObject);
+ } catch (ReflectionException e) {
+ log.warn(">>> CustomMetaObjectHandler处理过程中无相关字段,不做处理");
+ }
+ }
+
+ /**
+ * 获取用户唯一id
+ */
+ private Long getUserUniqueId() {
+ try {
+ return LoginContextHolder.me().getSysLoginUserId();
+ } catch (Exception e) {
+ //如果获取不到就返回-1
+ return -1L;
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/sqlfilter/DemoProfileSqlInterceptor.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/sqlfilter/DemoProfileSqlInterceptor.java
new file mode 100644
index 00000000..b0788839
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/mybatis/sqlfilter/DemoProfileSqlInterceptor.java
@@ -0,0 +1,85 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.mybatis.sqlfilter;
+
+import com.cn.xiaonuo.core.consts.SpringSecurityConstant;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.exception.DemoException;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
+import com.cn.xiaonuo.core.consts.SpringSecurityConstant;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.exception.DemoException;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.SystemMetaObject;
+import org.springframework.util.AntPathMatcher;
+
+import java.sql.Connection;
+
+/**
+ * 演示环境的sql过滤器,只放开select语句,其他语句都不放过
+ *
+ * @author yubaoshan
+ * @date 2020/5/5 12:21
+ */
+@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
+public class DemoProfileSqlInterceptor implements Interceptor {
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+
+ // 演示环境没开,直接跳过此过滤器
+ if (!ConstantContextHolder.getDemoEnvFlag()) {
+ return invocation.proceed();
+ }
+
+ StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
+ MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
+ MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
+
+ if (SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
+ return invocation.proceed();
+ } else {
+
+ //放开不进行安全过滤的接口
+ for (String notAuthResource : SpringSecurityConstant.NONE_SECURITY_URL_PATTERNS) {
+ AntPathMatcher antPathMatcher = new AntPathMatcher();
+ if (antPathMatcher.match(notAuthResource, HttpServletUtil.getRequest().getRequestURI())) {
+ return invocation.proceed();
+ }
+ }
+ throw new DemoException();
+ }
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/redis/FastJson2JsonRedisSerializer.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/redis/FastJson2JsonRedisSerializer.java
new file mode 100644
index 00000000..874b3e88
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/redis/FastJson2JsonRedisSerializer.java
@@ -0,0 +1,90 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.redis;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import java.nio.charset.Charset;
+
+/**
+ * redis序列化器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/30 18:30
+ */
+public class FastJson2JsonRedisSerializer implements RedisSerializer {
+
+ private final Class clazz;
+
+ static {
+ ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
+ }
+
+ /**
+ * 构造函数
+ *
+ * @author xuyuxiang
+ * @date 2020/4/8 19:12
+ */
+ public FastJson2JsonRedisSerializer(Class clazz) {
+ super();
+ this.clazz = clazz;
+ }
+
+ /**
+ * 序列化
+ *
+ * @author xuyuxiang
+ * @date 2020/4/8 19:12
+ */
+ @Override
+ public byte[] serialize(T t) throws SerializationException {
+ if (ObjectUtil.isEmpty(t)) {
+ return new byte[0];
+ }
+ return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(Charset.defaultCharset());
+ }
+
+ /**
+ * 反序列化
+ *
+ * @author xuyuxiang
+ * @date 2020/4/8 19:12
+ */
+ @Override
+ public T deserialize(byte[] bytes) throws SerializationException {
+ if (ObjectUtil.isEmpty(bytes)) {
+ return null;
+ }
+ String str = new String(bytes, Charset.defaultCharset());
+ return (T) JSON.parseObject(str, clazz);
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/scanner/ApiResourceScanner.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/scanner/ApiResourceScanner.java
new file mode 100644
index 00000000..867dc034
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/scanner/ApiResourceScanner.java
@@ -0,0 +1,210 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.core.scanner;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.context.resources.ApiResourceContext;
+import com.cn.xiaonuo.core.util.AopTargetUtil;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.context.resources.ApiResourceContext;
+import com.cn.xiaonuo.core.util.AopTargetUtil;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+/**
+ * 资源扫描器
+ *
+ * @author yubaoshan
+ * @date 2018/1/3 14:58
+ */
+public class ApiResourceScanner implements BeanPostProcessor {
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+
+ //如果controller是代理对象,则需要获取原始类的信息
+ Object aopTarget = AopTargetUtil.getTarget(bean);
+
+ if (aopTarget == null) {
+ aopTarget = bean;
+ }
+ Class> clazz = aopTarget.getClass();
+
+ //判断是不是控制器,不是控制器就略过
+ boolean controllerFlag = getControllerFlag(clazz);
+ if (!controllerFlag) {
+ return bean;
+ }
+
+ //扫描控制器的所有带ApiResource注解的方法
+ Set apiUrls = doScan(clazz);
+
+ //将扫描到的注解存储到缓存
+ persistApiResources(apiUrls);
+
+ return bean;
+ }
+
+
+ /**
+ * 判断一个类是否是控制器
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 18:23
+ */
+ private boolean getControllerFlag(Class> clazz) {
+ Annotation[] annotations = clazz.getAnnotations();
+
+ for (Annotation annotation : annotations) {
+ if (RestController.class.equals(annotation.annotationType()) || Controller.class.equals(annotation.annotationType())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 扫描整个类中包含的所有控制器
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 18:23
+ */
+ private Set doScan(Class> clazz) {
+
+ // 获取类头的@RequestMapping内容
+ String primaryMappingUrl = getRequestMappingUrl(clazz);
+
+ // 获取所有方法的RequestMapping的url
+ Set apiResources = CollectionUtil.newHashSet();
+ Method[] declaredMethods = clazz.getDeclaredMethods();
+ if (declaredMethods.length > 0) {
+ for (Method declaredMethod : declaredMethods) {
+ String requestMappingUrl = getRequestMappingUrl(declaredMethod);
+ apiResources.add(primaryMappingUrl + requestMappingUrl);
+ }
+ }
+ return apiResources;
+ }
+
+ /**
+ * 存储扫描到的api资源
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:43
+ */
+ private void persistApiResources(Set apiResources) {
+ ApiResourceContext.addBatchUrls(apiResources);
+ }
+
+ /**
+ * 获取@RequestMapping注解的url信息
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 17:43
+ */
+ private String getRequestMappingUrl(AnnotatedElement annotatedElement) {
+
+ RequestMapping requestMapping = annotatedElement.getAnnotation(RequestMapping.class);
+ GetMapping getMapping = annotatedElement.getAnnotation(GetMapping.class);
+ PostMapping postMapping = annotatedElement.getAnnotation(PostMapping.class);
+
+ // 分别判断三个注解中有没有value和path的值,优先级是 RequestMapping > GetMapping > PostMapping
+ if (requestMapping != null) {
+ String[] value = requestMapping.value();
+ String[] path = requestMapping.path();
+ if (value.length > 0) {
+ return getRequestMappingPath(value);
+ } else if (path.length > 0) {
+ return getRequestMappingPath(path);
+ }
+ } else if (getMapping != null) {
+ String[] value = getMapping.value();
+ String[] path = getMapping.path();
+ if (value.length > 0) {
+ return getRequestMappingPath(value);
+ } else if (path.length > 0) {
+ return getRequestMappingPath(path);
+ }
+ } else if (postMapping != null) {
+ String[] value = postMapping.value();
+ String[] path = postMapping.path();
+ if (value.length > 0) {
+ return getRequestMappingPath(value);
+ } else if (path.length > 0) {
+ return getRequestMappingPath(path);
+ }
+ }
+
+ return "";
+ }
+
+ /**
+ * 获取数组第一个字符串
+ *
+ * @author yubaoshan
+ * @date 2020/6/21 18:10
+ */
+ private String getRequestMappingPath(String[] strings) {
+ if (strings.length == 0) {
+ return "";
+ }
+ String result = strings[0];
+
+ // 如果RequestMapping的值是“/”直接返回
+ if (SymbolConstant.LEFT_DIVIDE.equals(result)) {
+ return result;
+ }
+
+ // 添加路径首部的"/"
+ if (!result.startsWith(SymbolConstant.LEFT_DIVIDE)) {
+ result = SymbolConstant.LEFT_DIVIDE + result;
+ }
+
+ // 则去掉尾部的"/"
+ if (result.endsWith(SymbolConstant.LEFT_DIVIDE)) {
+ result = StrUtil.removeSuffix(result, SymbolConstant.LEFT_DIVIDE);
+ }
+
+ return result;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/validator/XiaoNuoValidator.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/validator/XiaoNuoValidator.java
new file mode 100644
index 00000000..6c8a6cfd
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/core/validator/XiaoNuoValidator.java
@@ -0,0 +1,94 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+
+package com.cn.xiaonuo.sys.core.validator;
+
+import cn.hutool.log.Log;
+import com.cn.xiaonuo.core.context.group.RequestGroupContext;
+import com.cn.xiaonuo.core.context.group.RequestParamIdContext;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import org.springframework.validation.Errors;
+import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
+
+import java.beans.PropertyDescriptor;
+
+/**
+ * 用于真正校验参数之前缓存一下group的class类型
+ *
+ * 因为ConstraintValidator的自定义校验中获取不到当前进行的group
+ *
+ * @author xuyuxiang
+ * @date 2020/8/12 20:07
+ */
+public class XiaoNuoValidator extends LocalValidatorFactoryBean {
+
+ private static final Log log = Log.get();
+
+ @Override
+ public void validate(Object target, Errors errors, Object... validationHints) {
+
+ try {
+ if (validationHints.length > 0) {
+
+ // 如果是class类型,利用ThreadLocal缓存一下class类型
+ if (validationHints[0] instanceof Class) {
+
+ // 临时保存group的class值
+ RequestGroupContext.set((Class>) validationHints[0]);
+
+ // 临时保存字段为id的值
+ RequestParamIdContext.set(getParamIdValue(target));
+ }
+ }
+ super.validate(target, errors, validationHints);
+ } finally {
+ RequestGroupContext.clear();
+ RequestParamIdContext.clear();
+ }
+ }
+
+ /**
+ * 获取参数中的id的值,如果没有id字段就返回null
+ *
+ * @author xuyuxiang
+ * @date 2020/8/12 21:24
+ */
+ private Long getParamIdValue(Object target) {
+
+ try {
+ PropertyDescriptor prop = new PropertyDescriptor(CommonConstant.ID, target.getClass());
+ Object paramId = prop.getReadMethod().invoke(target);
+ if (paramId != null) {
+ if (paramId instanceof Long) {
+ return (Long) paramId;
+ }
+ }
+ } catch (Exception e) {
+ log.error(">>> 获取参数的id值时候出错:{}", e.getMessage());
+ }
+
+ return null;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/IndexController.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/IndexController.java
new file mode 100644
index 00000000..684b8291
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/IndexController.java
@@ -0,0 +1,50 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular;
+
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 首页控制器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 11:20
+ */
+@RestController
+public class IndexController {
+
+ /**
+ * 访问首页,提示语
+ *
+ * @author xuyuxiang
+ * @date 2020/4/8 19:27
+ */
+ @RequestMapping("/")
+ public String index() {
+ return CommonConstant.INDEX_TIPS;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/controller/SysAppController.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/controller/SysAppController.java
new file mode 100644
index 00000000..1b148fc5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/controller/SysAppController.java
@@ -0,0 +1,148 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.app.controller;
+
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.annotion.Permission;
+import com.cn.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
+import com.cn.xiaonuo.core.pojo.response.ResponseData;
+import com.cn.xiaonuo.core.pojo.response.SuccessResponseData;
+import com.cn.xiaonuo.sys.modular.app.param.SysAppParam;
+import com.cn.xiaonuo.sys.modular.app.service.SysAppService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 系统应用控制器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 21:25
+ */
+@RestController
+public class SysAppController {
+
+ @Resource
+ private SysAppService sysAppService;
+
+ /**
+ * 查询系统应用
+ *
+ * @author xuyuxiang
+ * @date 2020/3/20 21:23
+ */
+ @Permission
+ @GetMapping("/sysApp/page")
+ @BusinessLog(title = "系统应用_查询", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData page(SysAppParam sysAppParam) {
+ return new SuccessResponseData(sysAppService.page(sysAppParam));
+ }
+
+ /**
+ * 添加系统应用
+ *
+ * @author xuyuxiang
+ * @date 2020/3/25 14:44
+ */
+ @Permission
+ @PostMapping("/sysApp/add")
+ @BusinessLog(title = "系统应用_增加", opType = LogAnnotionOpTypeEnum.ADD)
+ public ResponseData add(@RequestBody @Validated(SysAppParam.add.class) SysAppParam sysAppParam) {
+ sysAppService.add(sysAppParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 删除系统应用
+ *
+ * @author xuyuxiang
+ * @date 2020/3/25 14:54
+ */
+ @Permission
+ @PostMapping("/sysApp/delete")
+ @BusinessLog(title = "系统应用_删除", opType = LogAnnotionOpTypeEnum.DELETE)
+ public ResponseData delete(@RequestBody @Validated(SysAppParam.delete.class) SysAppParam sysAppParam) {
+ sysAppService.delete(sysAppParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 编辑系统应用
+ *
+ * @author xuyuxiang
+ * @date 2020/3/25 14:54
+ */
+ @Permission
+ @PostMapping("/sysApp/edit")
+ @BusinessLog(title = "系统应用_编辑", opType = LogAnnotionOpTypeEnum.EDIT)
+ public ResponseData edit(@RequestBody @Validated(SysAppParam.edit.class) SysAppParam sysAppParam) {
+ sysAppService.edit(sysAppParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 查看系统应用
+ *
+ * @author xuyuxiang
+ * @date 2020/3/26 9:49
+ */
+ @Permission
+ @GetMapping("/sysApp/detail")
+ @BusinessLog(title = "系统应用_查看", opType = LogAnnotionOpTypeEnum.DETAIL)
+ public ResponseData detail(@Validated(SysAppParam.detail.class) SysAppParam sysAppParam) {
+ return new SuccessResponseData(sysAppService.detail(sysAppParam));
+ }
+
+ /**
+ * 系统应用列表
+ *
+ * @author xuyuxiang
+ * @date 2020/4/19 14:55
+ */
+ @Permission
+ @GetMapping("/sysApp/list")
+ @BusinessLog(title = "系统应用_列表", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData list(SysAppParam sysAppParam) {
+ return new SuccessResponseData(sysAppService.list(sysAppParam));
+ }
+
+ /**
+ * 设为默认应用
+ *
+ * @author xuyuxiang
+ * @date 2020/6/29 16:49
+ */
+ @Permission
+ @PostMapping("/sysApp/setAsDefault")
+ @BusinessLog(title = "系统应用_设为默认应用", opType = LogAnnotionOpTypeEnum.EDIT)
+ public ResponseData setAsDefault(@RequestBody @Validated(SysAppParam.detail.class) SysAppParam sysAppParam) {
+ sysAppService.setAsDefault(sysAppParam);
+ return new SuccessResponseData();
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/entity/SysApp.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/entity/SysApp.java
new file mode 100644
index 00000000..9a169a78
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/entity/SysApp.java
@@ -0,0 +1,72 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.app.entity;
+
+import com.cn.xiaonuo.core.pojo.base.entity.BaseEntity;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.cn.xiaonuo.core.pojo.base.entity.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 系统应用表
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 12:14
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@TableName("sys_app")
+public class SysApp extends BaseEntity {
+
+ /**
+ * 主键
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 名称
+ */
+ private String name;
+
+ /**
+ * 编码
+ */
+ private String code;
+
+ /**
+ * 是否默认激活(Y-是,N-否),只能有一个系统默认激活
+ * 用户登录后默认展示此系统菜单
+ */
+ private String active;
+
+ /**
+ * 状态(字典 0正常 1停用 2删除)
+ */
+ private Integer status;
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/enums/SysAppExceptionEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/enums/SysAppExceptionEnum.java
new file mode 100644
index 00000000..967c1be5
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/enums/SysAppExceptionEnum.java
@@ -0,0 +1,85 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.app.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.sys.core.consts.SysExpEnumConstant;
+
+/**
+ * 系统应用相关异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/26 10:11
+ */
+@ExpEnumType(module = SysExpEnumConstant.XIAONUO_SYS_MODULE_EXP_CODE, kind = SysExpEnumConstant.SYS_APP_EXCEPTION_ENUM)
+public enum SysAppExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 应用不存在
+ */
+ APP_NOT_EXIST(1, "应用不存在"),
+
+ /**
+ * 应用编码重复
+ */
+ APP_CODE_REPEAT(2, "应用编码重复,请检查code参数"),
+
+ /**
+ * 应用名称重复
+ */
+ APP_NAME_REPEAT(3, "应用名称重复,请检查name参数"),
+
+ /**
+ * 默认激活的系统只能有一个
+ */
+ APP_ACTIVE_REPEAT(4, "默认激活的系统只能有一个,请检查active参数"),
+
+ /**
+ * 该应用下有菜单
+ */
+ APP_CANNOT_DELETE(5, "该应用下有菜单,无法删除");
+
+ private final Integer code;
+
+ private final String message;
+
+ SysAppExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/mapper/SysAppMapper.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/mapper/SysAppMapper.java
new file mode 100644
index 00000000..32e824f0
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/mapper/SysAppMapper.java
@@ -0,0 +1,38 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.app.mapper;
+
+import com.cn.xiaonuo.sys.modular.app.entity.SysApp;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cn.xiaonuo.sys.modular.app.entity.SysApp;
+
+/**
+ * 系统应用mapper接口
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 16:17
+ */
+public interface SysAppMapper extends BaseMapper {
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/mapper/mapping/SysAppMapper.xml b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/mapper/mapping/SysAppMapper.xml
new file mode 100644
index 00000000..8443604f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/mapper/mapping/SysAppMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/param/SysAppParam.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/param/SysAppParam.java
new file mode 100644
index 00000000..3dd76ca6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/param/SysAppParam.java
@@ -0,0 +1,72 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.app.param;
+
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import com.cn.xiaonuo.core.validation.flag.FlagValue;
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import com.cn.xiaonuo.core.validation.flag.FlagValue;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 系统应用参数
+ *
+ * @author xuyuxiang
+ * @date 2020/3/24 20:53
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SysAppParam extends BaseParam {
+
+ /**
+ * 主键
+ */
+ @NotNull(message = "id不能为空,请检查id参数", groups = {edit.class, delete.class, detail.class})
+ private Long id;
+
+ /**
+ * 名称
+ */
+ @NotBlank(message = "名称不能为空,请检查name参数", groups = {add.class, edit.class})
+ private String name;
+
+ /**
+ * 编码
+ */
+ @NotBlank(message = "编码不能为空,请检查code参数", groups = {add.class, edit.class})
+ private String code;
+
+ /**
+ * 是否默认激活(Y-是,N-否),只能有一个系统默认激活
+ * 用户登录后默认展示此系统菜单
+ */
+ @NotBlank(message = "是否默认激活不能为空,请检查active参数", groups = {add.class, edit.class})
+ @FlagValue(message = "是否默认激活格式错误,正确格式应该Y或者N,请检查active参数", groups = {add.class, edit.class})
+ private String active;
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/service/SysAppService.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/service/SysAppService.java
new file mode 100644
index 00000000..fe572fb4
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/service/SysAppService.java
@@ -0,0 +1,118 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.app.service;
+
+import cn.hutool.core.lang.Dict;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.sys.modular.app.entity.SysApp;
+import com.cn.xiaonuo.sys.modular.app.param.SysAppParam;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * 系统应用service接口
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 16:14
+ */
+public interface SysAppService extends IService {
+
+ /**
+ * 获取用户应用相关信息
+ *
+ * @param userId 用户id
+ * @return 用户拥有的应用信息,格式:[{"code":"system","name":"系统应用","active":true}]
+ * @author xuyuxiang
+ * @date 2020/3/13 16:25
+ */
+ List getLoginApps(Long userId);
+
+ /**
+ * 查询系统应用
+ *
+ * @param sysAppParam 查询参数
+ * @return 查询分页结果
+ * @author xuyuxiang
+ * @date 2020/3/24 20:55
+ */
+ PageResult page(SysAppParam sysAppParam);
+
+ /**
+ * 添加系统应用
+ *
+ * @param sysAppParam 添加参数
+ * @author xuyuxiang
+ * @date 2020/3/25 14:57
+ */
+ void add(SysAppParam sysAppParam);
+
+ /**
+ * 删除系统应用
+ *
+ * @param sysAppParam 删除参数
+ * @author xuyuxiang
+ * @date 2020/3/25 14:57
+ */
+ void delete(SysAppParam sysAppParam);
+
+ /**
+ * 编辑系统应用
+ *
+ * @param sysAppParam 编辑参数
+ * @author xuyuxiang
+ * @date 2020/3/25 14:58
+ */
+ void edit(SysAppParam sysAppParam);
+
+ /**
+ * 查看系统应用
+ *
+ * @param sysAppParam 查看参数
+ * @return 系统应用
+ * @author xuyuxiang
+ * @date 2020/3/26 9:50
+ */
+ SysApp detail(SysAppParam sysAppParam);
+
+ /**
+ * 系统应用列表
+ *
+ * @param sysAppParam 查询参数
+ * @return 系统应用列表
+ * @author xuyuxiang
+ * @date 2020/4/19 14:56
+ */
+ List list(SysAppParam sysAppParam);
+
+ /**
+ * 设为默认应用
+ *
+ * @param sysAppParam 设为默认应用参数
+ * @author xuyuxiang
+ * @date 2020/6/29 16:49
+ */
+ void setAsDefault(SysAppParam sysAppParam);
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/service/impl/SysAppServiceImpl.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/service/impl/SysAppServiceImpl.java
new file mode 100644
index 00000000..ae1644d2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/app/service/impl/SysAppServiceImpl.java
@@ -0,0 +1,276 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.app.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.enums.CommonStatusEnum;
+import com.cn.xiaonuo.core.enums.YesOrNotEnum;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.factory.PageFactory;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.sys.core.enums.AdminTypeEnum;
+import com.cn.xiaonuo.sys.modular.app.entity.SysApp;
+import com.cn.xiaonuo.sys.modular.app.enums.SysAppExceptionEnum;
+import com.cn.xiaonuo.sys.modular.app.mapper.SysAppMapper;
+import com.cn.xiaonuo.sys.modular.app.param.SysAppParam;
+import com.cn.xiaonuo.sys.modular.app.service.SysAppService;
+import com.cn.xiaonuo.sys.modular.menu.service.SysMenuService;
+import com.cn.xiaonuo.sys.modular.user.entity.SysUser;
+import com.cn.xiaonuo.sys.modular.user.service.SysUserService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.enums.CommonStatusEnum;
+import com.cn.xiaonuo.core.enums.YesOrNotEnum;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.factory.PageFactory;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.sys.core.enums.AdminTypeEnum;
+import com.cn.xiaonuo.sys.modular.app.service.SysAppService;
+import com.cn.xiaonuo.sys.modular.menu.service.SysMenuService;
+import com.cn.xiaonuo.sys.modular.user.entity.SysUser;
+import com.cn.xiaonuo.sys.modular.user.service.SysUserService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * 系统应用service接口实现类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 16:15
+ */
+@Service
+public class SysAppServiceImpl extends ServiceImpl implements SysAppService {
+
+ @Resource
+ private SysUserService sysUserService;
+
+ @Resource
+ private SysMenuService sysMenuService;
+
+ @Override
+ public List getLoginApps(Long userId) {
+ List userAppDictList = CollectionUtil.newArrayList();
+
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysApp::getStatus, CommonStatusEnum.ENABLE.getCode());
+
+
+ SysUser sysUser = sysUserService.getById(userId);
+ Integer adminType = sysUser.getAdminType();
+
+ //如果不是超级管理员则有自己的菜单对应的应用编码
+ if (!AdminTypeEnum.SUPER_ADMIN.getCode().equals(adminType)) {
+ //获取用户菜单对应的应用编码集合
+ List appCodeList = sysMenuService.getUserMenuAppCodeList(userId);
+ //当应用编码不为空时,则限制查询范围
+ if (ObjectUtil.isNotEmpty(appCodeList)) {
+ queryWrapper.in(SysApp::getCode, appCodeList);
+ } else {
+ //没查到应用编码则直接返回
+ return userAppDictList;
+ }
+ }
+ //定义是否有默认激活的应用标志
+ AtomicBoolean hasDefaultActive = new AtomicBoolean(false);
+ //遍历
+ this.list(queryWrapper).forEach(sysApp -> {
+ Dict dict = Dict.create();
+ dict.put(CommonConstant.CODE, sysApp.getCode());
+ dict.put(CommonConstant.NAME, sysApp.getName());
+ //如果有默认激活的
+ if (YesOrNotEnum.Y.getCode().equals(sysApp.getActive())) {
+ hasDefaultActive.set(true);
+ dict.put("active", true);
+ //将其放在第一个
+ userAppDictList.add(0, dict);
+ } else {
+ dict.put("active", false);
+ userAppDictList.add(dict);
+ }
+
+ });
+ if (ObjectUtil.isNotEmpty(userAppDictList)) {
+ //如果默认激活的系统没有,则第一个为默认激活的系统
+ if (!hasDefaultActive.get()) {
+ Dict dict = userAppDictList.get(0);
+ dict.put("active", true);
+ }
+ }
+ return userAppDictList;
+ }
+
+ @Override
+ public PageResult page(SysAppParam sysAppParam) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ if (ObjectUtil.isNotNull(sysAppParam)) {
+ //根据名称模糊查询
+ if (ObjectUtil.isNotEmpty(sysAppParam.getName())) {
+ queryWrapper.like(SysApp::getName, sysAppParam.getName());
+ }
+ //根据编码模糊查询
+ if (ObjectUtil.isNotEmpty(sysAppParam.getCode())) {
+ queryWrapper.like(SysApp::getCode, sysAppParam.getCode());
+ }
+ }
+ queryWrapper.eq(SysApp::getStatus, CommonStatusEnum.ENABLE.getCode());
+ return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
+ }
+
+ @Override
+ public void add(SysAppParam sysAppParam) {
+ //校验参数,检查是否存在相同的名称和编码,以及默认激活的系统的数量是否合理
+ checkParam(sysAppParam, false);
+ SysApp sysApp = new SysApp();
+ BeanUtil.copyProperties(sysAppParam, sysApp);
+ sysApp.setStatus(CommonStatusEnum.ENABLE.getCode());
+ this.save(sysApp);
+ }
+
+ @Override
+ public void delete(SysAppParam sysAppParam) {
+ SysApp sysApp = this.querySysApp(sysAppParam);
+ String code = sysApp.getCode();
+ //该应用下是否有状态为正常的菜单
+ boolean hasMenu = sysMenuService.hasMenu(code);
+ //只要有,则不能删
+ if (hasMenu) {
+ throw new ServiceException(SysAppExceptionEnum.APP_CANNOT_DELETE);
+ }
+ sysApp.setStatus(CommonStatusEnum.DELETED.getCode());
+ this.updateById(sysApp);
+ }
+
+ @Override
+ public void edit(SysAppParam sysAppParam) {
+ SysApp sysApp = this.querySysApp(sysAppParam);
+ //校验参数,检查是否存在相同的名称和编码,以及默认激活的系统的数量是否合理
+ checkParam(sysAppParam, true);
+ BeanUtil.copyProperties(sysAppParam, sysApp);
+ //不能修改状态,用修改状态接口修改状态
+ sysApp.setStatus(null);
+ this.updateById(sysApp);
+ }
+
+ @Override
+ public SysApp detail(SysAppParam sysAppParam) {
+ return this.querySysApp(sysAppParam);
+ }
+
+ @Override
+ public List list(SysAppParam sysAppParam) {
+ LambdaQueryWrapper appQueryWrapper = new LambdaQueryWrapper<>();
+ appQueryWrapper.eq(SysApp::getStatus, CommonStatusEnum.ENABLE.getCode());
+ return this.list(appQueryWrapper);
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void setAsDefault(SysAppParam sysAppParam) {
+ SysApp currentApp = this.querySysApp(sysAppParam);
+ //所有已激活的改为未激活
+ LambdaQueryWrapper appQueryWrapper = new LambdaQueryWrapper<>();
+ appQueryWrapper.eq(SysApp::getStatus, CommonStatusEnum.ENABLE.getCode())
+ .eq(SysApp::getActive, YesOrNotEnum.Y.getCode());
+ this.list(appQueryWrapper).forEach(sysApp -> {
+ sysApp.setActive(YesOrNotEnum.N.getCode());
+ this.updateById(sysApp);
+ });
+ //当前的设置为已激活
+ currentApp.setActive(YesOrNotEnum.Y.getCode());
+ this.updateById(currentApp);
+ }
+
+ /**
+ * 校验参数,检查是否存在相同的名称和编码,以及默认激活的系统的数量是否合理
+ *
+ * @author xuyuxiang
+ * @date 2020/3/25 21:23
+ */
+ private void checkParam(SysAppParam sysAppParam, boolean isExcludeSelf) {
+ Long id = sysAppParam.getId();
+ String name = sysAppParam.getName();
+ String code = sysAppParam.getCode();
+ String active = sysAppParam.getActive();
+
+ // 查询名称有无重复
+ LambdaQueryWrapper appQueryWrapperByName = new LambdaQueryWrapper<>();
+ appQueryWrapperByName.eq(SysApp::getName, name)
+ .ne(SysApp::getStatus, CommonStatusEnum.DELETED.getCode());
+
+ // 查询编码有无重复
+ LambdaQueryWrapper appQueryWrapperByCode = new LambdaQueryWrapper<>();
+ appQueryWrapperByCode.eq(SysApp::getCode, code)
+ .ne(SysApp::getStatus, CommonStatusEnum.DELETED.getCode());
+
+ // 查询激活状态有无已经有Y的,也就是激活的
+ LambdaQueryWrapper appQueryWrapperByActive = new LambdaQueryWrapper<>();
+ appQueryWrapperByActive.eq(SysApp::getActive, active)
+ .ne(SysApp::getStatus, CommonStatusEnum.DELETED.getCode());
+
+ if (isExcludeSelf) {
+ appQueryWrapperByName.ne(SysApp::getId, id);
+ appQueryWrapperByCode.ne(SysApp::getId, id);
+ appQueryWrapperByActive.ne(SysApp::getId, id);
+ }
+ int countByName = this.count(appQueryWrapperByName);
+ int countByCode = this.count(appQueryWrapperByCode);
+ int countByActive = this.count(appQueryWrapperByActive);
+
+ if (countByName >= 1) {
+ throw new ServiceException(SysAppExceptionEnum.APP_NAME_REPEAT);
+ }
+ if (countByCode >= 1) {
+ throw new ServiceException(SysAppExceptionEnum.APP_CODE_REPEAT);
+ }
+
+ // 只判断激活状态为Y时候数量是否大于1了
+ if (countByActive >= 1 && YesOrNotEnum.Y.getCode().equals(sysAppParam.getActive())) {
+ throw new ServiceException(SysAppExceptionEnum.APP_ACTIVE_REPEAT);
+ }
+ }
+
+ /**
+ * 获取系统应用
+ *
+ * @author xuyuxiang
+ * @date 2020/3/26 9:56
+ */
+ private SysApp querySysApp(SysAppParam sysAppParam) {
+ SysApp sysApp = this.getById(sysAppParam.getId());
+ if (ObjectUtil.isNull(sysApp)) {
+ throw new ServiceException(SysAppExceptionEnum.APP_NOT_EXIST);
+ }
+ return sysApp;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/context/LoginContextSpringSecurityImpl.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/context/LoginContextSpringSecurityImpl.java
new file mode 100644
index 00000000..ee0c0e46
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/context/LoginContextSpringSecurityImpl.java
@@ -0,0 +1,291 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.auth.context;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.consts.SymbolConstant;
+import com.cn.xiaonuo.core.context.login.LoginContext;
+import com.cn.xiaonuo.core.exception.AuthException;
+import com.cn.xiaonuo.core.exception.enums.AuthExceptionEnum;
+import com.cn.xiaonuo.core.pojo.login.LoginEmpInfo;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.core.enums.AdminTypeEnum;
+import com.cn.xiaonuo.sys.modular.auth.service.AuthService;
+import com.cn.xiaonuo.sys.modular.user.entity.SysUser;
+import com.cn.xiaonuo.sys.modular.user.service.SysUserService;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 登录用户上下文实现类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 12:19
+ */
+@Component
+public class LoginContextSpringSecurityImpl implements LoginContext {
+
+ @Resource
+ private AuthService authService;
+
+ @Resource
+ private SysUserService sysUserService;
+
+ private LoginContextSpringSecurityImpl() {
+
+ }
+
+ /**
+ * 获取当前登录用户
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 14:42
+ */
+ @Override
+ public SysLoginUser getSysLoginUser() {
+ Authentication authentication = authService.getAuthentication();
+ if (ObjectUtil.isEmpty(authentication) || authentication.getPrincipal() instanceof String) {
+ throw new AuthException(AuthExceptionEnum.NO_LOGIN_USER);
+ } else {
+ return (SysLoginUser) authentication.getPrincipal();
+ }
+ }
+
+ /**
+ * 获取当前登录用户,如未登录,则返回null,不抛异常
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 14:42
+ */
+ @Override
+ public SysLoginUser getSysLoginUserWithoutException() {
+ Authentication authentication = authService.getAuthentication();
+ if (ObjectUtil.isEmpty(authentication) || authentication.getPrincipal() instanceof String) {
+ return null;
+ } else {
+ return (SysLoginUser) authentication.getPrincipal();
+ }
+ }
+
+ /**
+ * 获取当前登录用户的id
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:26
+ */
+ @Override
+ public Long getSysLoginUserId() {
+ return this.getSysLoginUser().getId();
+ }
+
+ /**
+ * 判断用户是否登录
+ *
+ * @author xuyuxiang
+ * @date 2020/3/18 19:23
+ */
+ @Override
+ public boolean hasLogin() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (ObjectUtil.isEmpty(authentication) || authentication.getPrincipal() instanceof String) {
+ return false;
+ } else {
+ return !(authentication instanceof AnonymousAuthenticationToken);
+ }
+ }
+
+ /**
+ * 获取当前登录的用户账号
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 8:49
+ */
+ @Override
+ public String getSysLoginUserAccount() {
+ return this.getSysLoginUser().getAccount();
+ }
+
+ /**
+ * 判断当前登录用户是否有某资源的访问权限
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 8:49
+ */
+ @Override
+ public boolean hasPermission(String requestUri) {
+ String removePrefix = StrUtil.removePrefix(requestUri, SymbolConstant.LEFT_DIVIDE);
+ String requestPermission = removePrefix.replaceAll(SymbolConstant.LEFT_DIVIDE, SymbolConstant.COLON);
+ return this.getSysLoginUser().getPermissions().contains(requestPermission);
+ }
+
+ /**
+ * 判断当前登录用户是否包含某个角色
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 8:55
+ */
+ @Override
+ public boolean hasRole(String roleCode) {
+ List roleCodeList = this.getLoginUserRoleCodeList();
+ return roleCodeList.contains(roleCode);
+ }
+
+ /**
+ * 判断当前登录用户是否包含任意一个角色
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 8:55
+ */
+ @Override
+ public boolean hasAnyRole(String roleCodes) {
+ boolean flag = false;
+ List loginUserRoleCodeList = this.getLoginUserRoleCodeList();
+ String[] roleCodeArr = StrUtil.split(roleCodes, SymbolConstant.COMMA);
+ for (String roleCode : roleCodeArr) {
+ if (loginUserRoleCodeList.contains(roleCode)) {
+ flag = true;
+ break;
+ }
+ }
+ return flag;
+ }
+
+ /**
+ * 管理员类型(0超级管理员 1非管理员)
+ * 判断当前登录用户是否是超级管理员
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 17:51
+ */
+ @Override
+ public boolean isSuperAdmin() {
+ return this.isAdmin(AdminTypeEnum.SUPER_ADMIN.getCode());
+ }
+
+ /**
+ * 判断当前登录用户是否包含所有角色
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 10:28
+ */
+ @Override
+ public boolean hasAllRole(String roleCodes) {
+ boolean flag = true;
+ List loginUserRoleCodeList = this.getLoginUserRoleCodeList();
+ String[] roleCodeArr = StrUtil.split(roleCodes, SymbolConstant.COMMA);
+ for (String roleCode : roleCodeArr) {
+ if (!loginUserRoleCodeList.contains(roleCode)) {
+ flag = false;
+ break;
+ }
+ }
+ return flag;
+ }
+
+ /**
+ * 判断当前登录用户是否是指定类型的管理员
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 11:43
+ */
+ private boolean isAdmin(Integer adminTypeCode) {
+ Integer adminType = this.getSysLoginUser().getAdminType();
+ boolean flag = false;
+ if (adminType.equals(adminTypeCode)) {
+ flag = true;
+ }
+ return flag;
+ }
+
+ /**
+ * 当前登录用户的数据范围(组织机构id集合)
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 17:20
+ */
+ @Override
+ public List getLoginUserDataScopeIdList() {
+ return this.getSysLoginUser().getDataScopes();
+ }
+
+ /**
+ * 获取当前登录用户的组织机构id集合
+ *
+ * @author xuyuxiang
+ * @date 2020/4/5 18:32
+ */
+ @Override
+ public Long getSysLoginUserOrgId() {
+ LoginEmpInfo loginEmpInfo = this.getSysLoginUser().getLoginEmpInfo();
+ if (ObjectUtil.isNotNull(loginEmpInfo)) {
+ if (ObjectUtil.isNotEmpty(loginEmpInfo.getOrgId())) {
+ return loginEmpInfo.getOrgId();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 获取当前登录用户的角色id集合
+ *
+ * @author xuyuxiang
+ * @date 2020/4/20 16:04
+ */
+ @Override
+ public List getLoginUserRoleIds() {
+ List resultList = CollectionUtil.newArrayList();
+ this.getSysLoginUser().getRoles().forEach(dict -> resultList.add(dict.getStr(CommonConstant.ID)));
+ return resultList;
+ }
+
+ @Override
+ public SysLoginUser getSysLoginUserUpToDate() {
+ SysLoginUser sysLoginUser = this.getSysLoginUser();
+ Long loginUserId = sysLoginUser.getId();
+ SysUser sysUser = sysUserService.getById(loginUserId);
+ //构造SysLoginUser
+ return authService.genSysLoginUser(sysUser);
+ }
+
+ /**
+ * 获取当前用户的角色编码集合
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 8:58
+ */
+ private List getLoginUserRoleCodeList() {
+ List roleCodeList = CollectionUtil.newArrayList();
+ this.getSysLoginUser().getRoles().forEach(dict -> roleCodeList.add(dict.getStr(CommonConstant.CODE)));
+ return roleCodeList;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/controller/SysLoginController.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/controller/SysLoginController.java
new file mode 100644
index 00000000..93c55de8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/controller/SysLoginController.java
@@ -0,0 +1,106 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.auth.controller;
+
+import cn.hutool.core.lang.Dict;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.context.login.LoginContextHolder;
+import com.cn.xiaonuo.core.pojo.response.ResponseData;
+import com.cn.xiaonuo.core.pojo.response.SuccessResponseData;
+import com.cn.xiaonuo.sys.modular.auth.service.AuthService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 登录控制器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 12:20
+ */
+@RestController
+public class SysLoginController {
+
+ @Resource
+ private AuthService authService;
+
+ /**
+ * 获取是否开启租户的标识
+ *
+ * @author xuyuxiang
+ * @date 2020/9/4
+ */
+ @GetMapping("/getTenantOpen")
+ public ResponseData getTenantOpen() {
+ return new SuccessResponseData(ConstantContextHolder.getTenantOpenFlag());
+ }
+
+ /**
+ * 账号密码登录
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 15:52
+ */
+ @PostMapping("/login")
+ public ResponseData login(@RequestBody Dict dict) {
+ String account = dict.getStr("account");
+ String password = dict.getStr("password");
+ String tenantCode = dict.getStr("tenantCode");
+
+ //如果系统开启了多租户开关,则添加租户的临时缓存
+ if (ConstantContextHolder.getTenantOpenFlag()) {
+ authService.cacheTenantInfo(tenantCode);
+ }
+
+ String token = authService.login(account, password);
+ return new SuccessResponseData(token);
+ }
+
+ /**
+ * 退出登录
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 15:02
+ */
+ @GetMapping("/logout")
+ public void logout() {
+ authService.logout();
+ }
+
+ /**
+ * 获取当前登录用户信息
+ *
+ * @author xuyuxiang
+ * @date 2020/3/23 17:57
+ */
+ @GetMapping("/getLoginUser")
+ public ResponseData getLoginUser() {
+ return new SuccessResponseData(LoginContextHolder.me().getSysLoginUserUpToDate());
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/factory/LoginUserFactory.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/factory/LoginUserFactory.java
new file mode 100644
index 00000000..f008ae46
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/factory/LoginUserFactory.java
@@ -0,0 +1,136 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.auth.factory;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import com.cn.xiaonuo.core.pojo.login.LoginEmpInfo;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.core.tenant.consts.TenantConstants;
+import com.cn.xiaonuo.core.tenant.context.TenantCodeHolder;
+import com.cn.xiaonuo.core.tenant.context.TenantDbNameHolder;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import com.cn.xiaonuo.core.util.IpAddressUtil;
+import com.cn.xiaonuo.core.util.UaUtil;
+import com.cn.xiaonuo.sys.modular.app.service.SysAppService;
+import com.cn.xiaonuo.sys.modular.emp.service.SysEmpService;
+import com.cn.xiaonuo.sys.modular.menu.service.SysMenuService;
+import com.cn.xiaonuo.sys.modular.role.service.SysRoleService;
+import com.cn.xiaonuo.sys.modular.user.service.SysUserService;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * 登录用户工厂类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 14:58
+ */
+public class LoginUserFactory {
+
+ private static final SysUserService sysUserService = SpringUtil.getBean(SysUserService.class);
+
+ private static final SysEmpService sysEmpService = SpringUtil.getBean(SysEmpService.class);
+
+ private static final SysAppService sysAppService = SpringUtil.getBean(SysAppService.class);
+
+ private static final SysMenuService sysMenuService = SpringUtil.getBean(SysMenuService.class);
+
+ private static final SysRoleService sysRoleService = SpringUtil.getBean(SysRoleService.class);
+
+ /**
+ * 填充登录用户相关信息
+ *
+ * @author xuyuxiang yubaoshan
+ * @date 2020/3/13 15:01
+ */
+ public static void fillLoginUserInfo(SysLoginUser sysLoginUser) {
+ HttpServletRequest request = HttpServletUtil.getRequest();
+ if (ObjectUtil.isNotNull(request)) {
+ sysLoginUser.setLastLoginIp(IpAddressUtil.getIp(request));
+ sysLoginUser.setLastLoginTime(DateTime.now().toString());
+ sysLoginUser.setLastLoginAddress(IpAddressUtil.getAddress(request));
+ sysLoginUser.setLastLoginBrowser(UaUtil.getBrowser(request));
+ sysLoginUser.setLastLoginOs(UaUtil.getOs(request));
+ Long userId = sysLoginUser.getId();
+
+ // 员工信息
+ LoginEmpInfo loginEmpInfo = sysEmpService.getLoginEmpInfo(userId);
+ sysLoginUser.setLoginEmpInfo(loginEmpInfo);
+
+ // 角色信息
+ List roles = sysRoleService.getLoginRoles(userId);
+ sysLoginUser.setRoles(roles);
+
+ // 权限信息
+ List permissions = sysMenuService.getLoginPermissions(userId);
+ sysLoginUser.setPermissions(permissions);
+
+ // 数据范围信息
+ List dataScopes = sysUserService.getUserDataScopeIdList(userId, loginEmpInfo.getOrgId());
+ sysLoginUser.setDataScopes(dataScopes);
+
+ // 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
+ List apps = sysAppService.getLoginApps(userId);
+ sysLoginUser.setApps(apps);
+
+ // 如果根本没有应用信息,则没有菜单信息
+ if (ObjectUtil.isEmpty(apps)) {
+ sysLoginUser.setMenus(CollectionUtil.newArrayList());
+ } else {
+ //AntDesign菜单信息,根据人获取,用于登录后展示菜单树,默认获取默认激活的系统的菜单
+ String defaultActiveAppCode = apps.get(0).getStr(CommonConstant.CODE);
+ sysLoginUser.setMenus(sysMenuService.getLoginMenusAntDesign(userId, defaultActiveAppCode));
+ }
+
+ //如果开启了多租户功能,则设置当前登录用户的租户标识
+ if (ConstantContextHolder.getTenantOpenFlag()) {
+ String tenantCode = TenantCodeHolder.get();
+ String dataBaseName = TenantDbNameHolder.get();
+ if (StrUtil.isNotBlank(tenantCode) && StrUtil.isNotBlank(dataBaseName)) {
+ Dict tenantInfo = Dict.create();
+ tenantInfo.set(TenantConstants.TENANT_CODE, tenantCode);
+ tenantInfo.set(TenantConstants.TENANT_DB_NAME, dataBaseName);
+ sysLoginUser.setTenants(tenantInfo);
+ }
+ //注意,这里remove不代表所有情况,在aop remove
+ TenantCodeHolder.remove();
+ TenantDbNameHolder.remove();
+ }
+
+ } else {
+ throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
+ }
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/service/AuthService.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/service/AuthService.java
new file mode 100644
index 00000000..09708765
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/service/AuthService.java
@@ -0,0 +1,135 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.auth.service;
+
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.sys.modular.user.entity.SysUser;
+import org.springframework.security.core.Authentication;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 认证相关service
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 14:14
+ */
+public interface AuthService {
+
+ /**
+ * 账号密码登录
+ *
+ * @param account 账号
+ * @param password 密码
+ * @return token
+ * @author xuyuxiang
+ * @date 2020/3/11 15:57
+ */
+ String login(String account, String password);
+
+ /**
+ * 根据已有用户信息登录
+ *
+ * @param sysUser 用户信息
+ * @return token
+ * @author xuyuxiang
+ * @date 2020/7/29 10:12
+ **/
+ String doLogin(SysUser sysUser);
+
+ /**
+ * 从request获取token
+ *
+ * @param request request
+ * @return token
+ * @author xuyuxiang
+ * @date 2020/3/13 11:41
+ */
+ String getTokenFromRequest(HttpServletRequest request);
+
+ /**
+ * 根据token获取登录用户信息
+ *
+ * @param token token
+ * @return 当前登陆的用户信息
+ * @author xuyuxiang
+ * @date 2020/3/13 11:59
+ */
+ SysLoginUser getLoginUserByToken(String token);
+
+ /**
+ * 退出登录
+ *
+ * @author xuyuxiang
+ * @date 2020/3/16 15:03
+ */
+ void logout();
+
+ /**
+ * 设置SpringSecurityContext上下文,方便获取用户
+ *
+ * @param sysLoginUser 当前登录用户信息
+ * @author xuyuxiang
+ * @date 2020/3/19 19:59
+ */
+ void setSpringSecurityContextAuthentication(SysLoginUser sysLoginUser);
+
+ /**
+ * 获取SpringSecurityContext中认证信息
+ *
+ * @return 认证信息
+ * @author xuyuxiang
+ * @date 2020/3/19 20:02
+ */
+ Authentication getAuthentication();
+
+ /**
+ * 校验token是否正确
+ *
+ * @param token token
+ * @author xuyuxiang
+ * @date 2020/5/28 9:57
+ */
+ void checkToken(String token);
+
+ /**
+ * 临时缓存租户信息
+ *
+ * @param tenantCode 多租户编码
+ * @author xuyuxiang
+ * @date 2020/9/3 21:22
+ */
+ void cacheTenantInfo(String tenantCode);
+
+ /**
+ * 根据系统用户构造用户登陆信息
+ *
+ * @param sysUser 系统用户
+ * @return 用户信息
+ * @author xuyuxiang
+ * @date 2020/9/20 15:21
+ **/
+ SysLoginUser genSysLoginUser(SysUser sysUser);
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/service/impl/AuthServiceImpl.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/service/impl/AuthServiceImpl.java
new file mode 100644
index 00000000..4b0e8b0f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/auth/service/impl/AuthServiceImpl.java
@@ -0,0 +1,363 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.auth.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.cn.xiaonuo.core.consts.CommonConstant;
+import com.cn.xiaonuo.core.context.constant.ConstantContextHolder;
+import com.cn.xiaonuo.core.dbs.CurrentDataSourceContext;
+import com.cn.xiaonuo.core.enums.CommonStatusEnum;
+import com.cn.xiaonuo.core.exception.AuthException;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.exception.enums.AuthExceptionEnum;
+import com.cn.xiaonuo.core.exception.enums.ServerExceptionEnum;
+import com.cn.xiaonuo.core.pojo.login.SysLoginUser;
+import com.cn.xiaonuo.core.tenant.context.TenantCodeHolder;
+import com.cn.xiaonuo.core.tenant.context.TenantDbNameHolder;
+import com.cn.xiaonuo.core.tenant.entity.TenantInfo;
+import com.cn.xiaonuo.core.tenant.exception.TenantException;
+import com.cn.xiaonuo.core.tenant.exception.enums.TenantExceptionEnum;
+import com.cn.xiaonuo.core.tenant.service.TenantInfoService;
+import com.cn.xiaonuo.core.util.HttpServletUtil;
+import com.cn.xiaonuo.core.util.IpAddressUtil;
+import com.cn.xiaonuo.sys.core.cache.UserCache;
+import com.cn.xiaonuo.sys.core.enums.LogSuccessStatusEnum;
+import com.cn.xiaonuo.sys.core.jwt.JwtPayLoad;
+import com.cn.xiaonuo.sys.core.jwt.JwtTokenUtil;
+import com.cn.xiaonuo.sys.core.log.LogManager;
+import com.cn.xiaonuo.sys.modular.auth.factory.LoginUserFactory;
+import com.cn.xiaonuo.sys.modular.auth.service.AuthService;
+import com.cn.xiaonuo.sys.modular.user.entity.SysUser;
+import com.cn.xiaonuo.sys.modular.user.service.SysUserService;
+import com.cn.xiaonuo.sys.modular.auth.factory.LoginUserFactory;
+import com.cn.xiaonuo.sys.modular.auth.service.AuthService;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.bcrypt.BCrypt;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+/**
+ * 认证相关service实现类
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 16:58
+ */
+@Service
+public class AuthServiceImpl implements AuthService, UserDetailsService {
+
+ @Resource
+ private SysUserService sysUserService;
+
+ @Resource
+ private UserCache userCache;
+
+ @Override
+ public String login(String account, String password) {
+
+ if (ObjectUtil.hasEmpty(account, password)) {
+ LogManager.me().executeLoginLog(account, LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_PWD_EMPTY.getMessage());
+ throw new AuthException(AuthExceptionEnum.ACCOUNT_PWD_EMPTY);
+ }
+
+ SysUser sysUser = sysUserService.getUserByCount(account);
+
+ //用户不存在,账号或密码错误
+ if (ObjectUtil.isEmpty(sysUser)) {
+ LogManager.me().executeLoginLog(account, LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_PWD_ERROR.getMessage());
+ throw new AuthException(AuthExceptionEnum.ACCOUNT_PWD_ERROR);
+ }
+
+ String passwordBcrypt = sysUser.getPassword();
+
+ //验证账号密码是否正确
+ if (ObjectUtil.isEmpty(passwordBcrypt) || !BCrypt.checkpw(password, passwordBcrypt)) {
+ LogManager.me().executeLoginLog(sysUser.getAccount(), LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_PWD_ERROR.getMessage());
+ throw new AuthException(AuthExceptionEnum.ACCOUNT_PWD_ERROR);
+ }
+
+ return doLogin(sysUser);
+ }
+
+ @Override
+ public String doLogin(SysUser sysUser) {
+
+ Integer sysUserStatus = sysUser.getStatus();
+
+ //验证账号是否被冻结
+ if (CommonStatusEnum.DISABLE.getCode().equals(sysUserStatus)) {
+ LogManager.me().executeLoginLog(sysUser.getAccount(), LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_FREEZE_ERROR.getMessage());
+ throw new AuthException(AuthExceptionEnum.ACCOUNT_FREEZE_ERROR);
+ }
+
+ //构造SysLoginUser
+ SysLoginUser sysLoginUser = this.genSysLoginUser(sysUser);
+
+ //构造jwtPayLoad
+ JwtPayLoad jwtPayLoad = new JwtPayLoad(sysUser.getId(), sysUser.getAccount());
+
+ //生成token
+ String token = JwtTokenUtil.generateToken(jwtPayLoad);
+
+ //缓存token与登录用户信息对应, 默认2个小时
+ this.cacheLoginUser(jwtPayLoad, sysLoginUser);
+
+ //设置最后登录ip和时间
+ sysUser.setLastLoginIp(IpAddressUtil.getIp(HttpServletUtil.getRequest()));
+ sysUser.setLastLoginTime(DateTime.now());
+
+ //更新用户登录信息
+ sysUserService.updateById(sysUser);
+
+ //登录成功,记录登录日志
+ LogManager.me().executeLoginLog(sysUser.getAccount(), LogSuccessStatusEnum.SUCCESS.getCode(), null);
+
+ //登录成功,设置SpringSecurityContext上下文,方便获取用户
+ this.setSpringSecurityContextAuthentication(sysLoginUser);
+
+ //如果开启限制单用户登陆,则踢掉原来的用户
+ Boolean enableSingleLogin = ConstantContextHolder.getEnableSingleLogin();
+ if (enableSingleLogin) {
+
+ //获取所有的登陆用户
+ Map allLoginUsers = userCache.getAllKeyValues();
+ for (Map.Entry loginedUserEntry : allLoginUsers.entrySet()) {
+
+ String loginedUserKey = loginedUserEntry.getKey();
+ SysLoginUser loginedUser = loginedUserEntry.getValue();
+
+ //如果账号名称相同,并且redis缓存key和刚刚生成的用户的uuid不一样,则清除以前登录的
+ if (loginedUser.getName().equals(sysUser.getName())
+ && !loginedUserKey.equals(jwtPayLoad.getUuid())) {
+ this.clearUser(loginedUserKey, loginedUser.getAccount());
+ }
+ }
+ }
+
+ //返回token
+ return token;
+ }
+
+ @Override
+ public String getTokenFromRequest(HttpServletRequest request) {
+ String authToken = request.getHeader(CommonConstant.AUTHORIZATION);
+ if (ObjectUtil.isEmpty(authToken)) {
+ return null;
+ } else {
+ //token不是以Bearer打头,则响应回格式不正确
+ if (!authToken.startsWith(CommonConstant.TOKEN_TYPE_BEARER)) {
+ throw new AuthException(AuthExceptionEnum.NOT_VALID_TOKEN_TYPE);
+ }
+ try {
+ authToken = authToken.substring(CommonConstant.TOKEN_TYPE_BEARER.length() + 1);
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new AuthException(AuthExceptionEnum.NOT_VALID_TOKEN_TYPE);
+ }
+ }
+
+ return authToken;
+ }
+
+ @Override
+ public SysLoginUser getLoginUserByToken(String token) {
+
+ //校验token,错误则抛异常
+ this.checkToken(token);
+
+ //根据token获取JwtPayLoad部分
+ JwtPayLoad jwtPayLoad = JwtTokenUtil.getJwtPayLoad(token);
+
+ //从redis缓存中获取登录用户
+ Object cacheObject = userCache.get(jwtPayLoad.getUuid());
+
+ //用户不存在则表示登录已过期
+ if (ObjectUtil.isEmpty(cacheObject)) {
+ throw new AuthException(AuthExceptionEnum.LOGIN_EXPIRED);
+ }
+
+ //转换成登录用户
+ SysLoginUser sysLoginUser = (SysLoginUser) cacheObject;
+
+ //用户存在, 无痛刷新缓存,在登录过期前活动的用户自动刷新缓存时间
+ this.cacheLoginUser(jwtPayLoad, sysLoginUser);
+
+ //返回用户
+ return sysLoginUser;
+ }
+
+ @Override
+ public void logout() {
+
+ HttpServletRequest request = HttpServletUtil.getRequest();
+
+ if (ObjectUtil.isNotNull(request)) {
+
+ //获取token
+ String token = this.getTokenFromRequest(request);
+
+ //如果token为空直接返回
+ if (ObjectUtil.isEmpty(token)) {
+ return;
+ }
+
+ //校验token,错误则抛异常,待确定
+ this.checkToken(token);
+
+ //根据token获取JwtPayLoad部分
+ JwtPayLoad jwtPayLoad = JwtTokenUtil.getJwtPayLoad(token);
+
+ //获取缓存的key
+ String loginUserCacheKey = jwtPayLoad.getUuid();
+ this.clearUser(loginUserCacheKey, jwtPayLoad.getAccount());
+
+ } else {
+ throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
+ }
+ }
+
+ @Override
+ public void setSpringSecurityContextAuthentication(SysLoginUser sysLoginUser) {
+ UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
+ new UsernamePasswordAuthenticationToken(
+ sysLoginUser,
+ null,
+ sysLoginUser.getAuthorities());
+ SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
+ }
+
+ @Override
+ public Authentication getAuthentication() {
+ return SecurityContextHolder.getContext().getAuthentication();
+ }
+
+ @Override
+ public void checkToken(String token) {
+ //校验token是否正确
+ Boolean tokenCorrect = JwtTokenUtil.checkToken(token);
+ if (!tokenCorrect) {
+ throw new AuthException(AuthExceptionEnum.REQUEST_TOKEN_ERROR);
+ }
+
+ //校验token是否失效
+ Boolean tokenExpired = JwtTokenUtil.isTokenExpired(token);
+ if (tokenExpired) {
+ throw new AuthException(AuthExceptionEnum.LOGIN_EXPIRED);
+ }
+ }
+
+ @Override
+ public void cacheTenantInfo(String tenantCode) {
+ if (StrUtil.isBlank(tenantCode)) {
+ return;
+ }
+
+ // 从spring容器中获取service,如果没开多租户功能,没引入相关包,这里会报错
+ TenantInfoService tenantInfoService = null;
+ try {
+ tenantInfoService = SpringUtil.getBean(TenantInfoService.class);
+ } catch (Exception e) {
+ throw new TenantException(TenantExceptionEnum.TENANT_MODULE_NOT_ENABLE_ERROR);
+ }
+
+ // 获取租户信息
+ TenantInfo tenantInfo = tenantInfoService.getByCode(tenantCode);
+ if (tenantInfo != null) {
+ String dbName = tenantInfo.getDbName();
+
+ // 租户编码的临时存放
+ TenantCodeHolder.put(tenantCode);
+
+ // 租户的数据库名称临时缓存
+ TenantDbNameHolder.put(dbName);
+
+ // 数据源信息临时缓存
+ CurrentDataSourceContext.setDataSourceType(dbName);
+ } else {
+ throw new TenantException(TenantExceptionEnum.CNAT_FIND_TENANT_ERROR);
+ }
+ }
+
+ @Override
+ public SysLoginUser loadUserByUsername(String account) throws UsernameNotFoundException {
+ SysLoginUser sysLoginUser = new SysLoginUser();
+ SysUser user = sysUserService.getUserByCount(account);
+ BeanUtil.copyProperties(user, sysLoginUser);
+ return sysLoginUser;
+ }
+
+ /**
+ * 根据key清空登陆信息
+ *
+ * @author xuyuxiang
+ * @date 2020/6/19 12:28
+ */
+ private void clearUser(String loginUserKey, String account) {
+ //获取缓存的用户
+ Object cacheObject = userCache.get(loginUserKey);
+
+ //如果缓存的用户存在,清除会话,否则表示该会话信息已失效,不执行任何操作
+ if (ObjectUtil.isNotEmpty(cacheObject)) {
+ //清除登录会话
+ userCache.remove(loginUserKey);
+ //创建退出登录日志
+ LogManager.me().executeExitLog(account);
+ }
+ }
+
+ /**
+ * 构造登录用户信息
+ *
+ * @author xuyuxiang
+ * @date 2020/3/12 17:32
+ */
+ @Override
+ public SysLoginUser genSysLoginUser(SysUser sysUser) {
+ SysLoginUser sysLoginUser = new SysLoginUser();
+ BeanUtil.copyProperties(sysUser, sysLoginUser);
+ LoginUserFactory.fillLoginUserInfo(sysLoginUser);
+ return sysLoginUser;
+ }
+
+ /**
+ * 缓存token与登录用户信息对应, 默认2个小时
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 14:51
+ */
+ private void cacheLoginUser(JwtPayLoad jwtPayLoad, SysLoginUser sysLoginUser) {
+ String redisLoginUserKey = jwtPayLoad.getUuid();
+ userCache.put(redisLoginUserKey, sysLoginUser);
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/controller/SysConfigController.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/controller/SysConfigController.java
new file mode 100644
index 00000000..945a9375
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/controller/SysConfigController.java
@@ -0,0 +1,138 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.consts.controller;
+
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.annotion.Permission;
+import com.cn.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
+import com.cn.xiaonuo.core.pojo.response.ResponseData;
+import com.cn.xiaonuo.core.pojo.response.SuccessResponseData;
+import com.cn.xiaonuo.sys.modular.consts.param.SysConfigParam;
+import com.cn.xiaonuo.sys.modular.consts.service.SysConfigService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+
+/**
+ * 参数配置控制器
+ *
+ * @author yubaoshan
+ * @date 2020/4/13 22:46
+ */
+@RestController
+public class SysConfigController {
+
+ @Resource
+ private SysConfigService sysConfigService;
+
+ /**
+ * 分页查询配置列表
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:10
+ */
+ @Permission
+ @GetMapping("/sysConfig/page")
+ @BusinessLog(title = "系统参数配置_查询", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData page(SysConfigParam sysConfigParam) {
+ return new SuccessResponseData(sysConfigService.page(sysConfigParam));
+ }
+
+ /**
+ * 系统参数配置列表
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:10
+ */
+ @Permission
+ @GetMapping("/sysConfig/list")
+ @BusinessLog(title = "系统参数配置_列表", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData list(SysConfigParam sysConfigParam) {
+ return new SuccessResponseData(sysConfigService.list(sysConfigParam));
+ }
+
+ /**
+ * 查看系统参数配置
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:12
+ */
+ @Permission
+ @GetMapping("/sysConfig/detail")
+ @BusinessLog(title = "系统参数配置_详情", opType = LogAnnotionOpTypeEnum.DETAIL)
+ public ResponseData detail(@Validated(SysConfigParam.detail.class) SysConfigParam sysConfigParam) {
+ return new SuccessResponseData(sysConfigService.detail(sysConfigParam));
+ }
+
+ /**
+ * 添加系统参数配置
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:11
+ */
+ @Permission
+ @PostMapping("/sysConfig/add")
+ @BusinessLog(title = "系统参数配置_增加", opType = LogAnnotionOpTypeEnum.ADD)
+ public ResponseData add(@RequestBody @Validated(SysConfigParam.add.class) SysConfigParam sysConfigParam) {
+ sysConfigService.add(sysConfigParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 删除系统参数配置
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:11
+ */
+ @Permission
+ @PostMapping("/sysConfig/delete")
+ @BusinessLog(title = "系统参数配置_删除", opType = LogAnnotionOpTypeEnum.DELETE)
+ public ResponseData delete(@RequestBody @Validated(SysConfigParam.delete.class) SysConfigParam sysConfigParam) {
+ sysConfigService.delete(sysConfigParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 编辑系统参数配置
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:11
+ */
+ @Permission
+ @PostMapping("/sysConfig/edit")
+ @BusinessLog(title = "系统参数配置_编辑", opType = LogAnnotionOpTypeEnum.EDIT)
+ public ResponseData edit(@RequestBody @Validated(SysConfigParam.edit.class) SysConfigParam sysConfigParam) {
+ sysConfigService.edit(sysConfigParam);
+ return new SuccessResponseData();
+ }
+
+}
+
+
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/entity/SysConfig.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/entity/SysConfig.java
new file mode 100644
index 00000000..af43e5d2
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/entity/SysConfig.java
@@ -0,0 +1,87 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.consts.entity;
+
+import com.cn.xiaonuo.core.pojo.base.entity.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ *
+ * 参数配置
+ *
+ *
+ * @author yubaoshan
+ * @date 2019/6/20 13:44
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@TableName("sys_config")
+public class SysConfig extends BaseEntity {
+
+ /**
+ * 主键
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 名称
+ */
+ private String name;
+
+ /**
+ * 编码
+ */
+ private String code;
+
+ /**
+ * 属性值
+ */
+ private String value;
+
+ /**
+ * 是否是系统参数(Y-是,N-否)
+ */
+ private String sysFlag;
+
+ /**
+ * 备注
+ */
+ @TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
+ private String remark;
+
+ /**
+ * 状态(字典 0正常 1停用 2删除)
+ */
+ private Integer status;
+
+ /**
+ * 常量所属分类的编码,来自于“常量的分类”字典
+ */
+ private String groupCode;
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/enums/SysConfigExceptionEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/enums/SysConfigExceptionEnum.java
new file mode 100644
index 00000000..6c3a0706
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/enums/SysConfigExceptionEnum.java
@@ -0,0 +1,90 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.consts.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.sys.core.consts.SysExpEnumConstant;
+
+/**
+ * 系统参数配置相关异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:24
+ */
+@ExpEnumType(module = SysExpEnumConstant.XIAONUO_SYS_MODULE_EXP_CODE, kind = SysExpEnumConstant.SYS_CONFIG_EXCEPTION_ENUM)
+public enum SysConfigExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 数据库连接配置不存在
+ */
+ DATA_SOURCE_NOT_EXIST(1, "数据库连接配置不存在,请检查spring.datasource配置"),
+
+ /**
+ * 系统参数配置不存在
+ */
+ CONFIG_NOT_EXIST(2, "系统参数配置不存在"),
+
+ /**
+ * 系统参数配置编码重复
+ */
+ CONFIG_CODE_REPEAT(3, "系统参数配置编码重复,请检查code参数"),
+
+ /**
+ * 系统参数配置名称重复
+ */
+ CONFIG_NAME_REPEAT(4, "系统参数配置名称重复,请检查name参数"),
+
+ /**
+ * 不能删除系统参数
+ */
+ CONFIG_SYS_CAN_NOT_DELETE(5, "系统参数配置不能删除"),
+
+ /**
+ * 常量分类在字典中未找到
+ */
+ NOT_EXIST_DICT_TYPE(6, "字典类型中未找到常量分类,请检查字典类型表");
+
+ private final Integer code;
+
+ private final String message;
+
+ SysConfigExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/mapper/SysConfigMapper.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/mapper/SysConfigMapper.java
new file mode 100644
index 00000000..35b2791f
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/mapper/SysConfigMapper.java
@@ -0,0 +1,40 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.consts.mapper;
+
+import com.cn.xiaonuo.sys.modular.consts.entity.SysConfig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cn.xiaonuo.sys.modular.consts.entity.SysConfig;
+
+/**
+ * 系统参数配置 Mapper 接口
+ *
+ * @author yubaoshan
+ * @date 2019/6/20 13:44
+ */
+public interface SysConfigMapper extends BaseMapper {
+
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/mapper/mapping/SysConfigMapper.xml b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/mapper/mapping/SysConfigMapper.xml
new file mode 100644
index 00000000..39027996
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/mapper/mapping/SysConfigMapper.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/param/SysConfigParam.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/param/SysConfigParam.java
new file mode 100644
index 00000000..b3c398f9
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/param/SysConfigParam.java
@@ -0,0 +1,86 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.consts.param;
+
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import com.cn.xiaonuo.core.validation.flag.FlagValue;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 系统参数配置参数
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 10:18
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SysConfigParam extends BaseParam {
+
+ /**
+ * 主键
+ */
+ @NotNull(message = "id不能为空,请检查id参数", groups = {edit.class, delete.class, detail.class})
+ private Long id;
+
+ /**
+ * 名称
+ */
+ @NotBlank(message = "名称不能为空,请检查name参数", groups = {add.class, edit.class})
+ private String name;
+
+ /**
+ * 编码
+ */
+ @NotBlank(message = "编码不能为空,请检查code参数", groups = {add.class, edit.class})
+ private String code;
+
+ /**
+ * 值
+ */
+ @NotBlank(message = "值不能为空,请检查value参数", groups = {add.class, edit.class})
+ private String value;
+
+ /**
+ * 是否是系统参数(Y-是,N-否)
+ */
+ @NotBlank(message = "是否是系统参数不能为空,请检查sysFlag参数", groups = {add.class, edit.class})
+ @FlagValue(message = "是否是系统参数格式错误,正确格式应该Y或者N,请检查sysFlag参数", groups = {add.class, edit.class})
+ private String sysFlag;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ /**
+ * 常量所属分类的编码,来自于“常量的分类”字典
+ */
+ @NotBlank(message = "值不能为空,请检查value参数", groups = {add.class, edit.class})
+ private String groupCode;
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/service/SysConfigService.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/service/SysConfigService.java
new file mode 100644
index 00000000..10443348
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/service/SysConfigService.java
@@ -0,0 +1,99 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.consts.service;
+
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.sys.modular.consts.entity.SysConfig;
+import com.cn.xiaonuo.sys.modular.consts.param.SysConfigParam;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * 系统参数配置service接口
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:14
+ */
+public interface SysConfigService extends IService {
+
+ /**
+ * 查询系统参数配置
+ *
+ * @param sysConfigParam 查询参数
+ * @return 查询分页结果
+ * @author xuyuxiang
+ * @date 2020/4/14 11:14
+ */
+ PageResult page(SysConfigParam sysConfigParam);
+
+ /**
+ * 查询系统参数配置
+ *
+ * @param sysConfigParam 查询参数
+ * @return 系统参数配置列表
+ * @author xuyuxiang
+ * @date 2020/4/14 11:14
+ */
+ List list(SysConfigParam sysConfigParam);
+
+ /**
+ * 查看系统参数配置
+ *
+ * @param sysConfigParam 查看参数
+ * @return 系统参数配置
+ * @author xuyuxiang
+ * @date 2020/4/14 11:15
+ */
+ SysConfig detail(SysConfigParam sysConfigParam);
+
+ /**
+ * 添加系统参数配置
+ *
+ * @param sysConfigParam 添加参数
+ * @author xuyuxiang
+ * @date 2020/4/14 11:14
+ */
+ void add(SysConfigParam sysConfigParam);
+
+ /**
+ * 删除系统参数配置
+ *
+ * @param sysConfigParam 删除参数
+ * @author xuyuxiang
+ * @date 2020/4/14 11:15
+ */
+ void delete(SysConfigParam sysConfigParam);
+
+ /**
+ * 编辑系统参数配置
+ *
+ * @param sysConfigParam 编辑参数
+ * @author xuyuxiang
+ * @date 2020/4/14 11:15
+ */
+ void edit(SysConfigParam sysConfigParam);
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/service/impl/SysConfigServiceImpl.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/service/impl/SysConfigServiceImpl.java
new file mode 100644
index 00000000..a4fe211c
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/consts/service/impl/SysConfigServiceImpl.java
@@ -0,0 +1,210 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.consts.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.cn.xiaonuo.core.context.constant.ConstantContext;
+import com.cn.xiaonuo.core.enums.CommonStatusEnum;
+import com.cn.xiaonuo.core.enums.YesOrNotEnum;
+import com.cn.xiaonuo.core.exception.ServiceException;
+import com.cn.xiaonuo.core.factory.PageFactory;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.sys.modular.consts.entity.SysConfig;
+import com.cn.xiaonuo.sys.modular.consts.enums.SysConfigExceptionEnum;
+import com.cn.xiaonuo.sys.modular.consts.mapper.SysConfigMapper;
+import com.cn.xiaonuo.sys.modular.consts.param.SysConfigParam;
+import com.cn.xiaonuo.sys.modular.consts.service.SysConfigService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+
+/**
+ * 系统参数配置service接口实现类
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:16
+ */
+@Service
+public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService {
+
+ @Override
+ public PageResult page(SysConfigParam sysConfigParam) {
+
+ //构造查询条件
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+
+ if (ObjectUtil.isNotNull(sysConfigParam)) {
+ //如果名称不为空,则带上名称搜素搜条件
+ if (ObjectUtil.isNotEmpty(sysConfigParam.getName())) {
+ queryWrapper.like(SysConfig::getName, sysConfigParam.getName());
+ }
+ //如果常量编码不为空,则带上常量编码搜素搜条件
+ if (ObjectUtil.isNotEmpty(sysConfigParam.getCode())) {
+ queryWrapper.like(SysConfig::getCode, sysConfigParam.getCode());
+ }
+ //如果分类编码不为空,则带上分类编码
+ if (ObjectUtil.isNotEmpty(sysConfigParam.getGroupCode())) {
+ queryWrapper.eq(SysConfig::getGroupCode, sysConfigParam.getGroupCode());
+ }
+ }
+
+ //查询未删除的
+ queryWrapper.ne(SysConfig::getStatus, CommonStatusEnum.DELETED.getCode());
+
+ //按类型升序排列,同类型的排在一起
+ queryWrapper.orderByDesc(SysConfig::getGroupCode);
+
+ //查询分页结果
+ return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
+ }
+
+ @Override
+ public List list(SysConfigParam sysConfigParam) {
+
+ //构造条件
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+
+ //查询未删除的
+ wrapper.ne(SysConfig::getStatus, CommonStatusEnum.DELETED.getCode());
+
+ return this.list(wrapper);
+ }
+
+ @Override
+ public SysConfig detail(SysConfigParam sysConfigParam) {
+ return this.querySysConfig(sysConfigParam);
+ }
+
+ @Override
+ public void add(SysConfigParam sysConfigParam) {
+
+ //1.校验参数,是否有重复的名称和编码,不排除当前记录
+ checkRepeatParam(sysConfigParam, false);
+
+ //2.构造实体
+ SysConfig sysConfig = new SysConfig();
+ BeanUtil.copyProperties(sysConfigParam, sysConfig);
+ sysConfig.setStatus(CommonStatusEnum.ENABLE.getCode());
+
+ //3.保存到库中
+ this.save(sysConfig);
+
+ //4.添加对应context
+ ConstantContext.putConstant(sysConfigParam.getCode(), sysConfigParam.getValue());
+ }
+
+ @Override
+ public void delete(SysConfigParam sysConfigParam) {
+
+ //1.根据id获取常量
+ SysConfig sysConfig = this.querySysConfig(sysConfigParam);
+
+ //2.不能删除系统参数
+ if (YesOrNotEnum.Y.getCode().equals(sysConfig.getSysFlag())) {
+ throw new ServiceException(SysConfigExceptionEnum.CONFIG_SYS_CAN_NOT_DELETE);
+ }
+
+ //3.设置状态为已删除
+ sysConfig.setStatus(CommonStatusEnum.DELETED.getCode());
+ this.updateById(sysConfig);
+
+ //4.删除对应context
+ ConstantContext.deleteConstant(sysConfigParam.getCode());
+ }
+
+ @Override
+ public void edit(SysConfigParam sysConfigParam) {
+
+ //1.根据id获取常量信息
+ SysConfig sysConfig = this.querySysConfig(sysConfigParam);
+
+ //2.校验参数,是否有重复的名称和编码,排除本条记录
+ checkRepeatParam(sysConfigParam, true);
+
+ //请求参数转化为实体
+ BeanUtil.copyProperties(sysConfigParam, sysConfig);
+ //不能修改状态,用修改状态接口修改状态
+ sysConfig.setStatus(null);
+
+ //3.更新记录
+ this.updateById(sysConfig);
+
+ //4.更新对应常量context
+ ConstantContext.putConstant(sysConfigParam.getCode(), sysConfigParam.getValue());
+ }
+
+ /**
+ * 校验参数,是否有重复的名称和编码
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:18
+ */
+ private void checkRepeatParam(SysConfigParam sysConfigParam, boolean isExcludeSelf) {
+ Long id = sysConfigParam.getId();
+ String name = sysConfigParam.getName();
+ String code = sysConfigParam.getCode();
+
+ //构建带name和code的查询条件
+ LambdaQueryWrapper queryWrapperByName = new LambdaQueryWrapper<>();
+ queryWrapperByName.eq(SysConfig::getName, name);
+
+ LambdaQueryWrapper queryWrapperByCode = new LambdaQueryWrapper<>();
+ queryWrapperByCode.eq(SysConfig::getCode, code);
+
+ //如果排除自己,则增加查询条件主键id不等于本条id
+ if (isExcludeSelf) {
+ queryWrapperByName.ne(SysConfig::getId, id);
+ queryWrapperByCode.ne(SysConfig::getId, id);
+ }
+ int countByName = this.count(queryWrapperByName);
+ int countByCode = this.count(queryWrapperByCode);
+
+ //如果存在重复的记录,抛出异常,直接返回前端
+ if (countByName >= 1) {
+ throw new ServiceException(SysConfigExceptionEnum.CONFIG_NAME_REPEAT);
+ }
+ if (countByCode >= 1) {
+ throw new ServiceException(SysConfigExceptionEnum.CONFIG_CODE_REPEAT);
+ }
+ }
+
+ /**
+ * 获取系统参数配置
+ *
+ * @author xuyuxiang
+ * @date 2020/4/14 11:19
+ */
+ private SysConfig querySysConfig(SysConfigParam sysConfigParam) {
+ SysConfig sysConfig = this.getById(sysConfigParam.getId());
+ if (ObjectUtil.isEmpty(sysConfig)) {
+ throw new ServiceException(SysConfigExceptionEnum.CONFIG_NOT_EXIST);
+ }
+ return sysConfig;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/controller/SysDictDataController.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/controller/SysDictDataController.java
new file mode 100644
index 00000000..f18a6977
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/controller/SysDictDataController.java
@@ -0,0 +1,149 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.controller;
+
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.annotion.Permission;
+import com.cn.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
+import com.cn.xiaonuo.core.pojo.response.ResponseData;
+import com.cn.xiaonuo.core.pojo.response.SuccessResponseData;
+import com.cn.xiaonuo.sys.modular.dict.param.SysDictDataParam;
+import com.cn.xiaonuo.sys.modular.dict.service.SysDictDataService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 系统字典值控制器
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:49
+ */
+@RestController
+public class SysDictDataController {
+
+ @Resource
+ private SysDictDataService sysDictDataService;
+
+ /**
+ * 查询系统字典值
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:50
+ */
+ @Permission
+ @GetMapping("/sysDictData/page")
+ @BusinessLog(title = "系统字典值_查询", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData page(SysDictDataParam sysDictDataParam) {
+ return new SuccessResponseData(sysDictDataService.page(sysDictDataParam));
+ }
+
+ /**
+ * 某个字典类型下所有的字典
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 21:03
+ */
+ @Permission
+ @GetMapping("/sysDictData/list")
+ @BusinessLog(title = "系统字典值_列表", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData list(@Validated(SysDictDataParam.list.class) SysDictDataParam sysDictDataParam) {
+ return new SuccessResponseData(sysDictDataService.list(sysDictDataParam));
+ }
+
+ /**
+ * 查看系统字典值
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:51
+ */
+ @Permission
+ @GetMapping("/sysDictData/detail")
+ @BusinessLog(title = "系统字典值_查看", opType = LogAnnotionOpTypeEnum.DETAIL)
+ public ResponseData detail(@Validated(SysDictDataParam.detail.class) SysDictDataParam sysDictDataParam) {
+ return new SuccessResponseData(sysDictDataService.detail(sysDictDataParam));
+ }
+
+ /**
+ * 添加系统字典值
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:50
+ */
+ @Permission
+ @PostMapping("/sysDictData/add")
+ @BusinessLog(title = "系统字典值_增加", opType = LogAnnotionOpTypeEnum.ADD)
+ public ResponseData add(@RequestBody @Validated(SysDictDataParam.add.class) SysDictDataParam sysDictDataParam) {
+ sysDictDataService.add(sysDictDataParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 删除系统字典值
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:50
+ */
+ @Permission
+ @PostMapping("/sysDictData/delete")
+ @BusinessLog(title = "系统字典值_删除", opType = LogAnnotionOpTypeEnum.DELETE)
+ public ResponseData delete(@RequestBody @Validated(SysDictDataParam.delete.class) SysDictDataParam sysDictDataParam) {
+ sysDictDataService.delete(sysDictDataParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 编辑系统字典值
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:51
+ */
+ @Permission
+ @PostMapping("/sysDictData/edit")
+ @BusinessLog(title = "系统字典值_编辑", opType = LogAnnotionOpTypeEnum.EDIT)
+ public ResponseData edit(@RequestBody @Validated(SysDictDataParam.edit.class) SysDictDataParam sysDictDataParam) {
+ sysDictDataService.edit(sysDictDataParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 修改状态
+ *
+ * @author yubaoshan
+ * @date 2020/5/1 9:43
+ */
+ @Permission
+ @PostMapping("/sysDictData/changeStatus")
+ @BusinessLog(title = "系统字典值_修改状态", opType = LogAnnotionOpTypeEnum.CHANGE_STATUS)
+ public ResponseData changeStatus(@RequestBody @Validated(SysDictDataParam.changeStatus.class) SysDictDataParam sysDictDataParam) {
+ sysDictDataService.changeStatus(sysDictDataParam);
+ return new SuccessResponseData();
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/controller/SysDictTypeController.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/controller/SysDictTypeController.java
new file mode 100644
index 00000000..ab3d6681
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/controller/SysDictTypeController.java
@@ -0,0 +1,172 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.controller;
+
+import com.cn.xiaonuo.core.annotion.BusinessLog;
+import com.cn.xiaonuo.core.annotion.Permission;
+import com.cn.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
+import com.cn.xiaonuo.core.pojo.response.ResponseData;
+import com.cn.xiaonuo.core.pojo.response.SuccessResponseData;
+import com.cn.xiaonuo.sys.modular.dict.param.SysDictTypeParam;
+import com.cn.xiaonuo.sys.modular.dict.service.SysDictTypeService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 系统字典类型控制器
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/31 20:49
+ */
+@RestController
+public class SysDictTypeController {
+
+ @Resource
+ private SysDictTypeService sysDictTypeService;
+
+ /**
+ * 分页查询系统字典类型
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/31 20:30
+ */
+ @Permission
+ @GetMapping("/sysDictType/page")
+ @BusinessLog(title = "系统字典类型_分页查询", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData page(SysDictTypeParam sysDictTypeParam) {
+ return new SuccessResponseData(sysDictTypeService.page(sysDictTypeParam));
+ }
+
+ /**
+ * 获取字典类型列表
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/31 21:03
+ */
+ @Permission
+ @GetMapping("/sysDictType/list")
+ @BusinessLog(title = "系统字典类型_列表", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData list(SysDictTypeParam sysDictTypeParam) {
+ return new SuccessResponseData(sysDictTypeService.list(sysDictTypeParam));
+ }
+
+ /**
+ * 获取字典类型下所有字典,举例,返回格式为:[{code:"M",value:"男"},{code:"F",value:"女"}]
+ *
+ * @author xuyuxiang,xuyuxiang yubaoshan
+ * @date 2020/3/31 21:18
+ */
+ @GetMapping("/sysDictType/dropDown")
+ @BusinessLog(title = "系统字典类型_下拉", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData dropDown(@Validated(SysDictTypeParam.dropDown.class) SysDictTypeParam sysDictTypeParam) {
+ return new SuccessResponseData(sysDictTypeService.dropDown(sysDictTypeParam));
+ }
+
+ /**
+ * 查看系统字典类型
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/31 20:31
+ */
+ @Permission
+ @GetMapping("/sysDictType/detail")
+ @BusinessLog(title = "系统字典类型_查看", opType = LogAnnotionOpTypeEnum.DETAIL)
+ public ResponseData detail(@Validated(SysDictTypeParam.detail.class) SysDictTypeParam sysDictTypeParam) {
+ return new SuccessResponseData(sysDictTypeService.detail(sysDictTypeParam));
+ }
+
+ /**
+ * 添加系统字典类型
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/31 20:30
+ */
+ @Permission
+ @PostMapping("/sysDictType/add")
+ @BusinessLog(title = "系统字典类型_增加", opType = LogAnnotionOpTypeEnum.ADD)
+ public ResponseData add(@RequestBody @Validated(SysDictTypeParam.add.class) SysDictTypeParam sysDictTypeParam) {
+ sysDictTypeService.add(sysDictTypeParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 删除系统字典类型
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/31 20:30
+ */
+ @Permission
+ @PostMapping("/sysDictType/delete")
+ @BusinessLog(title = "系统字典类型_删除", opType = LogAnnotionOpTypeEnum.DELETE)
+ public ResponseData delete(@RequestBody @Validated(SysDictTypeParam.delete.class) SysDictTypeParam sysDictTypeParam) {
+ sysDictTypeService.delete(sysDictTypeParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 编辑系统字典类型
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/31 20:31
+ */
+ @Permission
+ @PostMapping("/sysDictType/edit")
+ @BusinessLog(title = "系统字典类型_编辑", opType = LogAnnotionOpTypeEnum.EDIT)
+ public ResponseData edit(@RequestBody @Validated(SysDictTypeParam.edit.class) SysDictTypeParam sysDictTypeParam) {
+ sysDictTypeService.edit(sysDictTypeParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 修改状态
+ *
+ * @author yubaoshan
+ * @date 2020/4/30 22:20
+ */
+ @Permission
+ @PostMapping("/sysDictType/changeStatus")
+ @BusinessLog(title = "系统字典类型_修改状态", opType = LogAnnotionOpTypeEnum.CHANGE_STATUS)
+ public ResponseData changeStatus(@RequestBody @Validated(SysDictTypeParam.changeStatus.class) SysDictTypeParam sysDictTypeParam) {
+ sysDictTypeService.changeStatus(sysDictTypeParam);
+ return new SuccessResponseData();
+ }
+
+ /**
+ * 系统字典类型与字典值构造的树
+ *
+ * @author yubaoshan
+ * @date 2020/4/30 22:20
+ */
+ @GetMapping("/sysDictType/tree")
+ @BusinessLog(title = "系统字典类型_树", opType = LogAnnotionOpTypeEnum.QUERY)
+ public ResponseData tree() {
+ return new SuccessResponseData(sysDictTypeService.tree());
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/entity/SysDictData.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/entity/SysDictData.java
new file mode 100644
index 00000000..12658cf6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/entity/SysDictData.java
@@ -0,0 +1,79 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.entity;
+
+import com.cn.xiaonuo.core.pojo.base.entity.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 系统字典值表
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 12:08
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@TableName("sys_dict_data")
+public class SysDictData extends BaseEntity {
+
+ /**
+ * 主键
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 字典类型id
+ */
+ private Long typeId;
+
+ /**
+ * 值
+ */
+ private String value;
+
+ /**
+ * 编码
+ */
+ private String code;
+
+ /**
+ * 排序
+ */
+ private Integer sort;
+
+ /**
+ * 备注
+ */
+ @TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
+ private String remark;
+
+ /**
+ * 状态(字典 0正常 1停用 2删除)
+ */
+ private Integer status;
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/entity/SysDictType.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/entity/SysDictType.java
new file mode 100644
index 00000000..08504be8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/entity/SysDictType.java
@@ -0,0 +1,75 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.entity;
+
+import com.cn.xiaonuo.core.pojo.base.entity.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 系统字典类型表
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 12:08
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@TableName("sys_dict_type")
+public class SysDictType extends BaseEntity {
+
+ /**
+ * 主键
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 名称
+ */
+ private String name;
+
+ /**
+ * 编码
+ */
+ private String code;
+
+ /**
+ * 排序
+ */
+ private Integer sort;
+
+ /**
+ * 备注
+ */
+ @TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
+ private String remark;
+
+ /**
+ * 状态(字典 0正常 1停用 2删除)
+ */
+ private Integer status;
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/enums/SysDictDataExceptionEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/enums/SysDictDataExceptionEnum.java
new file mode 100644
index 00000000..92a11b8a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/enums/SysDictDataExceptionEnum.java
@@ -0,0 +1,70 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.sys.core.consts.SysExpEnumConstant;
+
+/**
+ * 系统字典值相关异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:47
+ */
+@ExpEnumType(module = SysExpEnumConstant.XIAONUO_SYS_MODULE_EXP_CODE, kind = SysExpEnumConstant.SYS_DICT_DATA_EXCEPTION_ENUM)
+public enum SysDictDataExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 字典值不存在
+ */
+ DICT_DATA_NOT_EXIST(1, "字典值不存在"),
+
+ /**
+ * 字典值编码重复
+ */
+ DICT_DATA_CODE_REPEAT(2, "字典值编码重复,请检查code参数");
+
+ private final Integer code;
+
+ private final String message;
+
+ SysDictDataExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/enums/SysDictTypeExceptionEnum.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/enums/SysDictTypeExceptionEnum.java
new file mode 100644
index 00000000..0993d56a
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/enums/SysDictTypeExceptionEnum.java
@@ -0,0 +1,75 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.enums;
+
+import com.cn.xiaonuo.core.annotion.ExpEnumType;
+import com.cn.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
+import com.cn.xiaonuo.core.factory.ExpEnumCodeFactory;
+import com.cn.xiaonuo.sys.core.consts.SysExpEnumConstant;
+
+/**
+ * 系统字典类型相关异常枚举
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:44
+ */
+@ExpEnumType(module = SysExpEnumConstant.XIAONUO_SYS_MODULE_EXP_CODE, kind = SysExpEnumConstant.SYS_DICT_TYPE_EXCEPTION_ENUM)
+public enum SysDictTypeExceptionEnum implements AbstractBaseExceptionEnum {
+
+ /**
+ * 字典类型不存在
+ */
+ DICT_TYPE_NOT_EXIST(1, "字典类型不存在"),
+
+ /**
+ * 字典类型编码重复
+ */
+ DICT_TYPE_CODE_REPEAT(2, "字典类型编码重复,请检查code参数"),
+
+ /**
+ * 字典类型名称重复
+ */
+ DICT_TYPE_NAME_REPEAT(3, "字典类型名称重复,请检查name参数");
+
+ private final Integer code;
+
+ private final String message;
+
+ SysDictTypeExceptionEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public Integer getCode() {
+ return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/SysDictDataMapper.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/SysDictDataMapper.java
new file mode 100644
index 00000000..856648bf
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/SysDictDataMapper.java
@@ -0,0 +1,50 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.mapper;
+
+import com.cn.xiaonuo.sys.modular.dict.entity.SysDictData;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import java.util.List;
+
+/**
+ * 系统字典值mapper接口
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 16:12
+ */
+public interface SysDictDataMapper extends BaseMapper {
+
+ /**
+ * 通过字典类型code获取字典编码值列表
+ *
+ * @param dictTypeCodes 字典类型编码集合
+ * @return 字典编码值列表
+ * @author xuyuxiang
+ * @date 2020/8/9 14:27
+ */
+ List getDictCodesByDictTypeCode(String[] dictTypeCodes);
+
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/SysDictTypeMapper.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/SysDictTypeMapper.java
new file mode 100644
index 00000000..2d2fcd9e
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/SysDictTypeMapper.java
@@ -0,0 +1,38 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.mapper;
+
+import com.cn.xiaonuo.sys.modular.dict.entity.SysDictType;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cn.xiaonuo.sys.modular.dict.entity.SysDictType;
+
+/**
+ * 系统字典类型mapper接口
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 16:11
+ */
+public interface SysDictTypeMapper extends BaseMapper {
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/mapping/SysDictDataMapper.xml b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/mapping/SysDictDataMapper.xml
new file mode 100644
index 00000000..d0fe03b6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/mapping/SysDictDataMapper.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ SELECT
+ dict.`code`
+ FROM
+ sys_dict_data dict
+ INNER JOIN sys_dict_type type ON dict.type_id = type.id
+ where type.code in
+
+ #{i}
+
+
+
+
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/mapping/SysDictTypeMapper.xml b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/mapping/SysDictTypeMapper.xml
new file mode 100644
index 00000000..f10fc723
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/mapper/mapping/SysDictTypeMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/param/SysDictDataParam.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/param/SysDictDataParam.java
new file mode 100644
index 00000000..d21790f8
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/param/SysDictDataParam.java
@@ -0,0 +1,84 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.param;
+
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 系统字典值参数
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:32
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SysDictDataParam extends BaseParam {
+
+ /**
+ * 主键
+ */
+ @NotNull(message = "id不能为空,请检查id参数", groups = {edit.class, delete.class, detail.class, changeStatus.class})
+ private Long id;
+
+ /**
+ * 字典类型id
+ */
+ @NotNull(message = "字典类型typeId不能为空,请检查typeId参数", groups = {list.class, add.class, edit.class})
+ private Long typeId;
+
+ /**
+ * 值
+ */
+ @NotBlank(message = "值不能为空,请检查value参数", groups = {add.class, edit.class})
+ private String value;
+
+ /**
+ * 编码
+ */
+ @NotBlank(message = "编码不能为空,请检查code参数", groups = {dropDown.class, add.class, edit.class})
+ private String code;
+
+ /**
+ * 排序
+ */
+ @NotNull(message = "排序不能为空,请检查sort参数", groups = {add.class, edit.class})
+ private Integer sort;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ /**
+ * 状态(字典 0正常 1停用 2删除)
+ */
+ @NotNull(message = "状态不能为空,请检查status参数", groups = changeStatus.class)
+ private Integer status;
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/param/SysDictTypeParam.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/param/SysDictTypeParam.java
new file mode 100644
index 00000000..ca5c185b
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/param/SysDictTypeParam.java
@@ -0,0 +1,78 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.param;
+
+import com.cn.xiaonuo.core.pojo.base.param.BaseParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 系统字典类型参数
+ *
+ * @author xuyuxiang
+ * @date 2020/3/31 20:32
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SysDictTypeParam extends BaseParam {
+
+ /**
+ * 主键
+ */
+ @NotNull(message = "id不能为空,请检查id参数", groups = {edit.class, delete.class, detail.class, changeStatus.class})
+ private Long id;
+
+ /**
+ * 名称
+ */
+ @NotBlank(message = "名称不能为空,请检查name参数", groups = {add.class, edit.class})
+ private String name;
+
+ /**
+ * 编码
+ */
+ @NotBlank(message = "编码不能为空,请检查code参数", groups = {add.class, edit.class, dropDown.class,})
+ private String code;
+
+ /**
+ * 排序
+ */
+ @NotNull(message = "排序不能为空,请检查sort参数", groups = {add.class, edit.class})
+ private Integer sort;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ /**
+ * 状态
+ */
+ @NotNull(message = "状态不能为空,请检查status参数", groups = {changeStatus.class})
+ private Integer status;
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/result/SysDictTreeNode.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/result/SysDictTreeNode.java
new file mode 100644
index 00000000..7287dfe7
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/result/SysDictTreeNode.java
@@ -0,0 +1,56 @@
+package com.cn.xiaonuo.sys.modular.dict.result;
+
+import com.cn.xiaonuo.core.pojo.base.node.BaseTreeNode;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 系统字典树
+ *
+ * @author xuyuxiang
+ * @date 2020/3/11 12:08
+ */
+@Data
+public class SysDictTreeNode implements BaseTreeNode {
+
+ /**
+ * id
+ */
+ private Long id;
+
+ /**
+ * 父id
+ */
+ private Long pid;
+
+ /**
+ * 编码-对应字典值的编码
+ */
+ private String code;
+
+ /**
+ * 名称-对应字典值的value
+ */
+ private String name;
+
+ /**
+ * 子节点集合
+ */
+ private List children;
+
+ @Override
+ public Long getId() {
+ return this.id;
+ }
+
+ @Override
+ public Long getPid() {
+ return this.pid;
+ }
+
+ @Override
+ public void setChildren(List children) {
+ this.children = children;
+ }
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/service/SysDictDataService.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/service/SysDictDataService.java
new file mode 100644
index 00000000..6f710e07
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/service/SysDictDataService.java
@@ -0,0 +1,137 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.service;
+
+import cn.hutool.core.lang.Dict;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.sys.modular.dict.entity.SysDictData;
+import com.cn.xiaonuo.sys.modular.dict.param.SysDictDataParam;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * 系统字典值service接口
+ *
+ * @author xuyuxiang
+ * @date 2020/3/13 16:10
+ */
+public interface SysDictDataService extends IService {
+
+ /**
+ * 查询系统字典值
+ *
+ * @param sysDictDataParam 查询参数
+ * @return 查询分页结果
+ * @author xuyuxiang
+ * @date 2020/3/31 20:53
+ */
+ PageResult page(SysDictDataParam sysDictDataParam);
+
+ /**
+ * 系统字典值列表
+ *
+ * @param sysDictDataParam 查询参数
+ * @return 系统字典值列表
+ * @author xuyuxiang
+ * @date 2020/3/31 21:07
+ */
+ List list(SysDictDataParam sysDictDataParam);
+
+ /**
+ * 添加系统字典值
+ *
+ * @param sysDictDataParam 添加参数
+ * @author xuyuxiang
+ * @date 2020/3/31 20:53
+ */
+ void add(SysDictDataParam sysDictDataParam);
+
+ /**
+ * 删除系统字典值
+ *
+ * @param sysDictDataParam 删除参数
+ * @author xuyuxiang
+ * @date 2020/3/31 20:54
+ */
+ void delete(SysDictDataParam sysDictDataParam);
+
+ /**
+ * 编辑系统字典值
+ *
+ * @param sysDictDataParam 编辑参数
+ * @author xuyuxiang
+ * @date 2020/3/31 20:54
+ */
+ void edit(SysDictDataParam sysDictDataParam);
+
+ /**
+ * 查看系统字典值
+ *
+ * @param sysDictDataParam 查看参数
+ * @return 系统字典值
+ * @author xuyuxiang
+ * @date 2020/3/31 20:54
+ */
+ SysDictData detail(SysDictDataParam sysDictDataParam);
+
+ /**
+ * 根据typeId下拉
+ *
+ * @param dictTypeId 字典类型id
+ * @return 增强版hashMap,格式:[{"code:":"1", "value":"正常"}]
+ * @author xuyuxiang yubaoshan
+ * @date 2020/3/31 21:27
+ */
+ List getDictDataListByDictTypeId(Long dictTypeId);
+
+ /**
+ * 根据typeId删除
+ *
+ * @param dictTypeId 字典类型id
+ * @author xuyuxiang
+ * @date 2020/4/1 10:27
+ */
+ void deleteByTypeId(Long dictTypeId);
+
+ /**
+ * 修改状态
+ *
+ * @param sysDictDataParam 修改参数
+ * @author yubaoshan
+ * @date 2020/5/1 9:44
+ */
+ void changeStatus(SysDictDataParam sysDictDataParam);
+
+ /**
+ * 根据字典类型获取字典的code值
+ *
+ * @param dictTypeCodes 字典类型编码集合
+ * @return 字典编码值列表
+ * @author xuyuxiang
+ * @date 2020/8/9 14:18
+ */
+ List getDictCodesByDictTypeCode(String... dictTypeCodes);
+}
diff --git a/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/service/SysDictTypeService.java b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/service/SysDictTypeService.java
new file mode 100644
index 00000000..6c260ff6
--- /dev/null
+++ b/xiaonuo-base/xiaonuo-system/src/main/java/com/cn/xiaonuo/sys/modular/dict/service/SysDictTypeService.java
@@ -0,0 +1,129 @@
+/*
+Copyright [2020] [https://www.xiaonuo.vip]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XiaoNuo采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+
+1.请不要删除和修改根目录下的LICENSE文件。
+2.请不要删除和修改XiaoNuo源码头部的版权声明。
+3.请保留源码和相关描述文件的项目出处,作者声明等。
+4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuo/xiaonuo-vue
+6.若您的项目无法满足以上几点,可申请商业授权,获取XiaoNuo商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package com.cn.xiaonuo.sys.modular.dict.service;
+
+import cn.hutool.core.lang.Dict;
+import com.cn.xiaonuo.core.pojo.page.PageResult;
+import com.cn.xiaonuo.sys.modular.dict.entity.SysDictType;
+import com.cn.xiaonuo.sys.modular.dict.param.SysDictTypeParam;
+import com.cn.xiaonuo.sys.modular.dict.result.SysDictTreeNode;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cn.xiaonuo.sys.modular.dict.result.SysDictTreeNode;
+
+import java.util.List;
+
+/**
+ * 系统字典类型service接口
+ *
+ * @author xuyuxiang,xuyuxiang
+ * @date 2020/3/13 16:10
+ */
+public interface SysDictTypeService extends IService