shiro、springboot、vue、elementUI CDN模式前后端分离的权限管理demo 附源码
shiro、springboot、vue、elementUI CDN模式前后端分离的权限管理demo 附源码
源码下载地址
https://github.com/Aizhuxueliang/springboot_shiro.git
前提你电脑的安装好这些工具:jdk8、idea、maven、git、mysql
;
shiro的主要概念
- Shiro是一个强大的简单易用的Java安全框架,主要用来更便捷的认证、授权、加密、会话管理、与Web集成、缓存等;
- Shiro使用起来小而简单;
- spring中有spring security ,是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单;
- shiro不依赖于spring,shiro不仅可以实现web应用的权限管理,还可以实现c/s系统,分布式系统权限管理;
在应用程序角度来观察如何使用Shiro完成工作
Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject 都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager 交互;且它管理着所有Subject;可以看出它是Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
shiro官方文档
https://shiro.apache.org/architecture.html
前端CDN的方式使用elementUI、vue、vue-router、axios画页面
CDN(内容分发网络)本身是指一种请求资源的方式。说白了就是在本地,通过script头去请求对应的脚本资源的一种方式。我在这里要说的就是直接引用 (demo是直接引用的,注意电脑联网
)或者下载Vue.js和elementUI.js放在本地,进行项目开发的方式。而不是通过npm包管理工具去下载vue包。
cdn方式引入elementui 官方API:https://element.eleme.cn/#/zh-CN/component/installation
cdn方式引入vue-router官方API:https://router.vuejs.org/zh/guide/#html
DEMO的整体流程设计
技术层面了解完就该设计业务流程了,如图:
demo整体结构
如图:
主要功能页面
1、登录
2、用户查询
3、分配角色
4、删除角色
5、新建用户
6、分配权限
7、新建角色
主要代码
com/example/demo/controller/UserCtrl.java
package com.example.demo.controller;import com.example.demo.entity.Role;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;/*** 控制层*/
@RestController
@RequestMapping("/user")
public class UserCtrl {@Autowiredprivate UserService userService;/*** 登录接口** @param user user* @return resultMap*/@RequestMapping(value = "/login", method = RequestMethod.POST)public Map<String, Object> login(@RequestBody User user) {//拿到主体Subject subject = SecurityUtils.getSubject();try {UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword());subject.login(usernamePasswordToken);Object permissions = subject.getSession().getAttribute("permissions");subject.getSession().removeAttribute("permissions");return userService.resultMap("permissions", permissions, "token", subject.getSession().getId(), "", "");}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 获取用户的角色类型** @param user user* @return resultMap*/@RequestMapping(value = "/findRoleListByUserId", method = RequestMethod.POST)public Map<String, Object> findRoleListByUserId(@RequestBody User user) {try{return userService.findRoleListByUserId(user.getId());}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 获取角色的权限类型** @param role role* @return resultMap*/@RequestMapping(value = "/findPermissionListByRoleId", method = RequestMethod.POST)public Map<String, Object> findPermissionListByRoleId(@RequestBody Role role) {try{return userService.findPermissionListByRoleId(role.getId());}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 更新角色具有的权限** @param role role* @return resultMap*/@RequestMapping(value = "/updateRolePermission", method = RequestMethod.POST)public Map<String, Object> updateRolePermission(@RequestBody Role role) {try{return userService.updateRolePermission(role);}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 删除角色** @param role role* @return resultMap*/@RequestMapping(value = "/removeRole", method = RequestMethod.POST)public Map<String, Object> removeRole(@RequestBody Role role) {try{return userService.removeRole(role);}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 添加角色** @param role role* @return resultMap*/@RequestMapping(value = "/addRole", method = RequestMethod.POST)public Map<String, Object> addRole(@RequestBody Role role) {try{return userService.addRole(role);}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 更新用户具有的角色** @param user user* @return resultMap*/@RequestMapping(value = "/updateUserRole", method = RequestMethod.POST)public Map<String, Object> updateUserRole(@RequestBody User user) {try{return userService.updateUserRole(user);}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 根据用户提供的条件分页查询用户** @param user user* @return resultMap*/@RequestMapping(value = "/queryUserListPage", method = RequestMethod.POST)public Map<String, Object> queryUserListPage(@RequestBody User user) {try{return userService.queryUserListPage(user);}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 删除用户** @param user user* @return resultMap*/@RequestMapping(value = "/removeUser", method = RequestMethod.POST)public Map<String, Object> removeUser(@RequestBody User user) {try{return userService.removeUser(user);}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}/*** 新增用户** @param user user* @return resultMap*/@RequestMapping(value = "/insertUser", method = RequestMethod.POST)public Map<String, Object> insertUser(@RequestBody User user) {try{return userService.insertUser(user);}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}}
com/example/demo/service/UserService.java
package com.example.demo.service;import com.example.demo.entity.Permission;
import com.example.demo.entity.Role;
import com.example.demo.entity.User;
import com.example.demo.mapper.PermissionMapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.mapper.RoleMapper;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.*;
import java.util.stream.Collectors;/*** 服务层*/
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RoleMapper roleMapper;@Autowiredprivate PermissionMapper permissionMapper;public User findUserByName(String userName) {User user = userMapper.findUserByName(userName);//用户角色的集合List<Role> roleList = roleMapper.findRoleListByUserId(user.getId());user.setRoleList(roleList);return user;}public Map<String, Object> findRoleListByUserId(int userId){//用戶具有的角色集合List<Role> beRoleList = roleMapper.findRoleListByUserIdNotPermission(userId);//用戶没有的角色集合List<Role> notRoleList = roleMapper.findNotRoleListByUserIdNotPermission(userId);//所有角色集合Collection<?> allRoleList = CollectionUtils.union(beRoleList, notRoleList);return this.resultMap("beRoleList", beRoleList, "notRoleList", notRoleList, "allRoleList", allRoleList);}@Transactional(rollbackFor = {Exception.class})public Map<String, Object> updateUserRole(User user){int removeUserRole = userMapper.removeUserRoleByUserId(user.getId());int addUserRole = 0;if (user.getRoleList().size()!=0 && user.getRoleList()!=null){addUserRole = userMapper.addUserRole(user);}return this.resultMap("removeUserRole", removeUserRole, "addUserRole", addUserRole, "", "");}public Map<String, Object> findPermissionListByRoleId(int roleId){//角色具有的权限集合List<Permission> bePermissionList = permissionMapper.findByPermissionListByRoleId(roleId);//角色没有的权限集合List<Permission> notPermissionList = permissionMapper.findNotPermissionListByRoleId(roleId);//所有权限集合Collection<?> allPermissionList = CollectionUtils.union(bePermissionList, notPermissionList);return this.resultMap("bePermissionList", bePermissionList, "notPermissionList", notPermissionList, "allPermissionList", allPermissionList);}@Transactional(rollbackFor = {Exception.class})public Map<String, Object> updateRolePermission(Role role){int removeRolePermission = roleMapper.removeRolePermissionByRoleId(role.getId());int addRolePermission = 0;if (role.getPermissionList().size()!=0 && role.getPermissionList()!=null){addRolePermission = roleMapper.addRolePermission(role);}return this.resultMap("removeRolePermission", removeRolePermission, "addRolePermission", addRolePermission, "", "");}@Transactional(rollbackFor = {Exception.class})public Map<String, Object> removeRole(Role role){int removeRolePermission = roleMapper.removeRolePermissionByRoleId(role.getId());int removeRole = roleMapper.removeRoleByRoleId(role.getId());int removeUserRole = userMapper.removeUserRoleByRoleId(role.getId());return this.resultMap("removeRolePermission", removeRolePermission, "removeRole", removeRole, "removeUserRole", removeUserRole);}public Map<String, Object> queryUserListPage(User user){//当前页页码int pageNow = user.getReserve1() < 1 ? 1 : user.getReserve1();//当前页第一行索引user.setReserve1(5*(pageNow - 1));List<User> userListPage = userMapper.queryUserListPage(user);int userRowCount = userMapper.getUserRowCount(user);return this.resultMap("userListPage", userListPage, "userRowCount", userRowCount, "", "");}public Map<String, Object> addRole(Role role){int addRole = roleMapper.addRole(role);return this.resultMap("addRole", addRole, "", "", "", "");}@Transactional(rollbackFor = {Exception.class})public Map<String, Object> removeUser(User user){int removeUser = userMapper.removeUserByUserId(user.getId());int removeUserRole = userMapper.removeUserRoleByUserId(user.getId());return this.resultMap("removeUser", removeUser, "removeUserRole", removeUserRole, "", "");}public Map<String, Object> insertUser(User user) {int addUser = userMapper.insertUser(user);return this.resultMap("addUser", addUser, "", "", "", "");}public Map<String, Object> resultMap(String str1, Object obj1, String str2, Object obj2, String str3, Object obj3){Map<String, Object> resultMap = new HashMap<>();if (!"".equals(str1) || !"".equals(obj1))resultMap.put(str1, obj1);if (!"".equals(str2) || !"".equals(obj2))resultMap.put(str2, obj2);if (!"".equals(str3) || !"".equals(obj3))resultMap.put(str3, obj3);return resultMap;}}
CDN模式下的vue、vue-router、template模板挂载操作
参考:src/main/resources/static/index.html
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><!-- import CSS --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app"><router-view></router-view>
</div>
<template id="sign"><div class="handle"><div class="handle-input"><div class="high70"><span>用户名称:</span><el-inputv-model="username"placeholder="请输入用户名称"clearable></el-input></div><div class="high70"><span>密码:</span><el-inputv-model="password"placeholder="请输入密码"clearableshow-password></el-input></div><el-button @click="login" plain>登录</el-button></div></div>
</template>
<template id="manager"><el-tabs :tab-position="tabPosition"><el-tab-pane label="用户设置" v-if="permissionsFlag.query_user || permissionsFlag.add_user || permissionsFlag.allot_roles || permissionsFlag.remove_user"><el-row type="flex" justify="center"><el-col :span="18"><div class="handle-area"><div class="demo-input" v-show="permissionsFlag.query_user || permissionsFlag.add_user || permissionsFlag.allot_roles || permissionsFlag.remove_user"><span>用户ID:</span><el-inputv-model="id"placeholder="请输入用户ID"type="number"size="medium"clearable></el-input><span>用户名称:</span><el-inputv-model="username"placeholder="请输入用户名称"size="medium"clearable></el-input><el-button:plain="true"@click="queryUserList"icon="el-icon-search"size="medium">查询用户</el-button></div><el-buttonv-show="permissionsFlag.add_user":plain="true"@click="handleAddUser"icon="el-icon-user"size="medium">新建用户</el-button></div><el-table:data="tableData"borderhighlight-current-row><el-table-columnprop="id"label="用户ID"></el-table-column><el-table-columnprop="username"label="用户名称"></el-table-column><el-table-columnlabel="操作"><template slot-scope="scope"><el-buttonv-show="permissionsFlag.allot_roles"type="text"icon="el-icon-set-up"@click="handleEditUser(scope.$index, scope.row)">分配角色</el-button><el-buttonv-show="permissionsFlag.remove_user"type="text"icon="el-icon-remove-outline"@click="handleDeleteUser(scope.$index, scope.row)">删除用户</el-button></template></el-table-column></el-table><el-paginationlayout="total, prev, pager, next, jumper":total="userRowCount":page-size="5":current-page.sync="currentPage"@current-change="queryUserListPage":hide-on-single-page="hidePageFlag"background></el-pagination></el-col></el-row><el-dialog :title="roleTitle" :visible.sync="dialogEditUser" :before-close="handleClose"><el-transferv-model="transferValue":data="transferData":titles="['待分配角色', '已分配角色']"></el-transfer><span slot="footer" class="dialog-footer"><el-button @click="handleClose">取 消</el-button><el-button type="primary" @click="assignRoles">确 定</el-button></span></el-dialog><el-dialog title="新建用户" :visible.sync="dialogAddUser" :before-close="handleClose"><div class="high70"><span>用户名称:</span><el-inputv-model="username"placeholder="请输入用户名称"size="medium"clearable></el-input></div><div class="high70"><span>密码:</span><el-inputv-model="password"placeholder="请输入密码"size="medium"clearableshow-password></el-input></div><div class="high70"><span>再次输入密码:</span><el-inputv-model="password1"placeholder="请再次输入密码"size="medium"show-password></el-input></div><div class="high70"><span>备注:</span><el-inputv-model="reserve"placeholder="请输入用户备注"size="medium"></el-input></div><span slot="footer" class="dialog-footer"><el-button @click="handleClose">取 消</el-button><el-button type="primary" @click="insertUser">确 定</el-button></span></el-dialog></el-tab-pane><el-tab-pane label="角色设置" v-if="permissionsFlag.allot_roles || permissionsFlag.query_role || permissionsFlag.add_role || permissionsFlag.remove_role || permissionsFlag.allot_permission"><el-row type="flex" justify="center"><el-col :span="18"><div class="handle-area"><el-buttonv-show="permissionsFlag.allot_roles || permissionsFlag.query_role || permissionsFlag.add_role || permissionsFlag.remove_role || permissionsFlag.allot_permission":plain="true"@click="queryRoleList"icon="el-icon-search"size="medium">角色查询</el-button><el-buttonv-show="permissionsFlag.add_role":plain="true"@click="handleAddRole"icon="el-icon-circle-plus-outline"size="medium">新建角色</el-button></div><el-table:data="roleData"borderhighlight-current-row><el-table-columnprop="id"label="角色ID"></el-table-column><el-table-columnprop="name"label="角色名称"></el-table-column><el-table-columnprop="description"label="角色描述"></el-table-column><el-table-columnlabel="操作"><template slot-scope="scope"><el-buttonv-show="permissionsFlag.allot_permission"type="text"icon="el-icon-s-operation"@click="handleEditRole(scope.$index, scope.row)">分配权限</el-button><el-buttonv-show="permissionsFlag.remove_role"type="text"icon="el-icon-remove-outline"@click="handleDeleteRole(scope.$index, scope.row)">删除角色</el-button></template></el-table-column></el-table></el-col></el-row><el-dialog :title="permissionsTitle" :visible.sync="dialogEditRole" :before-close="handleClose"><el-checkbox-group v-model="checkedPermissions" class="el-checkbox-group-dialog"><el-checkbox v-for="permission in permissions" :label="permission.name" :key="permission.name">{{permission.description}}</el-checkbox></el-checkbox-group><span slot="footer" class="dialog-footer"><el-button @click="handleClose">取 消</el-button><el-button type="primary" @click="assignPermissions">确 定</el-button></span></el-dialog><el-dialog title="新建角色" :visible.sync="dialogAddRole" :before-close="handleClose"><div class="high70"><span>角色名称:</span><el-inputv-model="name"placeholder="请输入角色名称"size="medium"></el-input></div><div class="high70"><span>角色描述:</span><el-inputv-model="description"placeholder="请输入角色描述"size="medium"></el-input></div><span slot="footer" class="dialog-footer"><el-button @click="handleClose">取 消</el-button><el-button type="primary" @click="insertRole">确 定</el-button></span></el-dialog></el-tab-pane><el-tab-pane label="权限列表" v-if="permissionsFlag.allot_permission"><el-row type="flex" justify="center"><el-col :span="18"><div class="handle-area"><el-buttonv-show="permissionsFlag.allot_permission":plain="true"@click="queryPermissionList"icon="el-icon-search"size="medium">权限查询</el-button></div><el-table:data="permissionData"borderhighlight-current-row><el-table-columnprop="id"label="权限ID"></el-table-column><el-table-columnprop="name"label="权限名称"></el-table-column><el-table-columnprop="description"label="权限描述"></el-table-column></el-table></el-col></el-row></el-tab-pane></el-tabs>
</template>
</body>
<!-- import Vue before Element -->
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- import Axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- import Router -->
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
<script>const Sign = {props: ['todo'],template: '#sign',data() {return {username: '',password: '',permissionsStr: [],token: ''}},methods: {login() {axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/login',data: JSON.stringify({username: this.username,password: this.password})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){this.username = '';this.password = '';ELEMENT.Notification.error({title: '登录失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}this.permissionsStr = response.data.permissions;this.token = response.data.token;this.$router.push({name: 'manager',params: {token: this.token,permissionsStr: this.permissionsStr}});}).catch(error => {console.log(error);ELEMENT.Message(error);});}},mounted() {console.log('组件Sign被挂载了');}};const Manager = {// todo-item 组件现在接受一个// "prop",类似于一个自定义 attribute。// 这个 prop 名为 todo。props: ['todo'],template: '#manager',data() {return {// 角色信息roleData: [],roleId: null,name: '',description: '',dialogEditRole: false,dialogAddRole: false,permissions: [],checkedPermissions: [],permissionList: [],permissionsTitle: '',// 权限信息permissionData: [],// 穿梭框transferValue: [],transferData: [],// 表格及分页tableData: [],tabPosition: 'top',userRowCount: 0,currentPage: 0,hidePageFlag: true,// 弹框dialogEditUser: false,// 分配角色弹框dialogAddUser: false,// 新建用户弹框// 用户信息allRoleList: [],roleList: [],id: null,username: '',password: '',password1: '',reserve: '',roleTitle: '',permissionsStr: [],permissionsFlag: {query_user: false,add_user: false,remove_user: false,allot_roles: false,query_role: false,add_role: false,remove_role: false,allot_permission: false},token: ''}},methods: {queryPermissionList() {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/findPermissionListByRoleId',data: JSON.stringify({id: 0})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '查询失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}this.permissionData = response.data.allPermissionList;}).catch(error => {console.log(error);ELEMENT.Message(error);});},queryRoleList() {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/findRoleListByUserId',data: JSON.stringify({id: 0})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '查询失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}this.roleData = response.data.allRoleList;}).catch(error => {console.log(error);ELEMENT.Message(error);});},handleEditRole(index, row){axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/findPermissionListByRoleId',data: JSON.stringify({id: row.id})}).then(response => {console.log(response.data);if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '查询失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}this.permissions = response.data.allPermissionList;for(let item of response.data.bePermissionList){this.checkedPermissions.push(item.name);}this.roleId = row.id;this.name = row.name;this.permissionsTitle = '为角色'+row.name+'分配权限';this.dialogEditRole = true;}).catch(error => {console.log(error);ELEMENT.Message(error);});},handleDeleteRole(index, row){ELEMENT.MessageBox.confirm('此操作将永久删除角色'+row.name+', 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/removeRole',data: JSON.stringify({id: row.id})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '角色'+row.name+',删除失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}if (response.data.removeRolePermission >= 0 && response.data.removeRole >= 0 && response.data.removeUserRole >= 0) {this.queryRoleList();ELEMENT.Notification({title: '删除成功',message: '角色'+row.name+',删除成功!',type: 'success',position: 'top-right',showClose: false,offset: 110});}}).catch(error => {ELEMENT.Message({ type: 'info', message: error});});}).catch(() => {ELEMENT.Message({ type: 'info', message: '已取消删除'});});},handleAddRole(){this.dialogAddRole = true;this.name = '';this.description = '';},insertRole(){axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/addRole',data: JSON.stringify({name: this.name,description: this.description})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '角色'+this.name+',添加失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});this.dialogAddRole = false;this.name = '';this.description = '';return;}if(response.data.addRole > 0) {this.queryRoleList();ELEMENT.Notification({title: '添加成功',message: '角色'+this.name+',添加成功!',type: 'success',position: 'top-right',showClose: false,offset: 110});this.dialogAddRole = false;this.name = '';this.description = '';}console.log(response.data);}).catch(error => {ELEMENT.Message({ type: 'info', message: error});});},assignPermissions(){for(let item of this.permissions){for(let i in this.checkedPermissions){if (this.checkedPermissions[i] == item.name) {this.permissionList.push(item);}}}axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/updateRolePermission',data: JSON.stringify({id: this.roleId,permissionList: this.permissionList,})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){this.dialogEditRole = false;ELEMENT.Notification.error({title: '为角色'+this.name+',分配权限失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});this.roleId = null;this.name = null;this.permissions = [];this.checkedPermissions = [];this.permissionList = [];this.permissionsTitle = '';return;}if (response.data.removeRolePermission >= 0 && response.data.addRolePermission >= 0) {this.dialogEditRole = false;ELEMENT.Notification({title: '更新成功',message: '为角色'+this.name+',分配权限成功!',type: 'success',position: 'top-right',showClose: false,offset: 110});this.roleId = null;this.name = null;this.permissions = [];this.checkedPermissions = [];this.permissionList = [];this.permissionsTitle = '';}console.log(response.data);}).catch(error => {console.log(error);ELEMENT.Message(error);});},// ------------------------用户设置部分--------------queryUserList() {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/queryUserListPage',data: JSON.stringify({id: this.id,username: this.username})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '查询用户失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}console.log(response.data);this.tableData = response.data.userListPage;this.userRowCount = response.data.userRowCount;if(this.userRowCount > 5) {this.hidePageFlag = false;} else {this.hidePageFlag = true;}this.currentPage = 1;}).catch(error => {console.log(error);ELEMENT.Message(error);});},queryUserListPage() {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/queryUserListPage',data: JSON.stringify({id: this.id,username: this.username,reserve1: this.currentPage})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '查询用户失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}console.log(response.data);this.tableData = response.data.userListPage;this.userRowCount = response.data.userRowCount;if(this.userRowCount > 5) {this.hidePageFlag = false;} else {this.hidePageFlag = true;}}).catch(error => {console.log(error);ELEMENT.Message(error);});},handleEditUser(index, row) {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/findRoleListByUserId',data: JSON.stringify({id: row.id})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){this.dialogEditUser = false;ELEMENT.Notification.error({title: '为用户'+row.username+'分配角色失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}console.log(response.data);for(let item of response.data.allRoleList){this.transferData.push({key: item.id,label: item.description});}for(let item of response.data.beRoleList){this.transferValue.push(item.id);}this.id = row.id;this.username = row.username;this.allRoleList = response.data.allRoleList;this.roleTitle = '为用户'+row.username+'分配角色';this.dialogEditUser = true;}).catch(error => {console.log(error);ELEMENT.Message(error);});},assignRoles() {for(let item of this.allRoleList){for(let i in this.transferValue){if (this.transferValue[i] == item.id) {this.roleList.push(item);}}}axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/updateUserRole',data: JSON.stringify({id: this.id,username: this.username,roleList: this.roleList})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){this.dialogEditUser = false;ELEMENT.Notification.error({title: '为用户'+row.username+'分配角色失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});this.id = null;this.username = '';this.allRoleList = [];this.roleList = [];this.transferData = [];this.transferValue = [];return;}if (response.data.removeUserRole >= 0 && response.data.addUserRole >= 0) {this.dialogEditUser = false;ELEMENT.Notification({title: '更新成功',message: '为用户'+this.username+',分配角色成功!',type: 'success',position: 'top-right',showClose: false,offset: 110});this.id = null;this.username = '';this.allRoleList = [];this.roleList = [];this.transferData = [];this.transferValue = [];}console.log(response.data);}).catch(error => {console.log(error);});},handleDeleteUser(index, row) {//this.ruleForm = Object.assign({}, row, index); //这句是关键!!!ELEMENT.MessageBox.confirm('此操作将永久删除用户'+row.id+', 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/removeUser',data: JSON.stringify({id: row.id})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '用户'+row.username+',删除失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}if (response.data.removeUser >= 0 && response.data.removeUserRole >= 0) {if(((this.userRowCount - 1) % 5 == 0) && ((this.userRowCount - 1) / 5 == (this.currentPage - 1))) {this.currentPage = this.currentPage - 1;}this.queryUserListPage();ELEMENT.Notification({title: '删除成功',message: '用户'+row.username+',删除成功!',type: 'success',position: 'top-right',showClose: false,offset: 110});}}).catch(error => {ELEMENT.Message({ type: 'info', message: error});});}).catch(() => {ELEMENT.Message({ type: 'info', message: '已取消删除'});});},handleClose() {// 用户设置this.dialogEditUser = false;this.dialogAddUser = false;this.id = null;this.username = '';this.password = '';this.password1 = '';this.reserve = '';this.allRoleList = [];this.roleList = [];this.transferData = [];this.transferValue = [];this.roleTitle = '';// 角色设置this.dialogEditRole = false;this.dialogAddRole = false;this.roleId = null;this.name = null;this.permissions = [];this.checkedPermissions = [];this.permissionList = [];this.permissionsTitle = '';ELEMENT.Message({message: '取消操作,系统不会保留任何更改',type:'warning'});},handleAddUser(){this.dialogAddUser = true;this.id = null;this.username = '';this.password = '';this.password1 = '';this.reserve = '';},insertUser() {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/insertUser',data: JSON.stringify({username: this.username,password: this.password,reserve: this.reserve})}).then(response => {if(response.data.addUser > 0) {this.dialogAddUser = false;this.password = '';this.password1 = '';this.reserve = '';this.queryUserList();ELEMENT.Notification({title: '添加成功',message: '用户'+this.username+',添加成功!',type: 'success',position: 'top-right',showClose: false,offset: 110});}if(typeof response.data.error !== 'undefined' || response.data.error != null){this.dialogAddUser = false;this.password = '';this.password1 = '';this.reserve = '';this.queryUserList();ELEMENT.Notification.error({title: '用户'+this.username+',添加失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}console.log(response.data);}).catch(error => {ELEMENT.Message({ type: 'info', message: error});});}},mounted() {console.log('组件Manager被挂载了');},created() {this.permissionsStr = this.$route.params.permissionsStr;this.token = this.$route.params.token;for(let key in this.permissionsFlag){for(let i in this.permissionsStr){if(this.permissionsStr[i] == key){this.permissionsFlag[key] = true;}}console.log(key + '---' + this.permissionsFlag[key])}}};const router = new VueRouter({routes:[{path: '/',name: 'sign',component: Sign},{path: '/manager',name: 'manager',component: Manager}]});new Vue({router,el: '#app',data: {},methods: {}})
</script>
<style>.el-pagination {display: flex;justify-content: flex-end;align-items: center;height: 60px;}.el-transfer {display: flex;justify-content: center;align-items: center;}.handle-area {display: flex;align-items: center;justify-content: space-between;height: 70px;flex-wrap: nowrap;}.demo-input {display: flex;align-items: center;}.demo-input span {white-space: nowrap;}.el-dialog__body {display: flex;flex-direction: column;justify-content: center;flex-wrap: nowrap;height: 280px;}.el-checkbox-group-dialog {height: 100%;display: flex;flex-direction: column;justify-content: center;margin: auto;}.el-checkbox {height: 30px;line-height: 30px;}.high70 {height: 70px;}.handle {position: absolute;width: 100%;height: 100%;top: 0;left: 0;margin: 0;background-image: url(banner.jpg);background-position: center;background-repeat: no-repeat;background-size: cover;overflow: hidden;display: flex;justify-content: center;align-items: center;}.handle-input {display: flex;flex-direction: column;}
</style>
</html>
具体看index.html 代码,如果没看懂,参考网址:
https://blog.csdn.net/laow1314/article/details/109323527
https://blog.csdn.net/qq_29722281/article/details/85016524
权限相关表
最基础的CRUD操作无法体现shiro的功能,需引入RBAC (Role-Based Access Control)思想,配置至少需要三张主表分别代表用户(user)、角色(role)、权限(permission),及两个附表分别是用户和角色(user_role),角色与权限(role_permission)表,表结构如下:
对应的实体如下:
1、com/example/demo/entity/User.java
package com.example.demo.entity;import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.*;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;@Data
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {/*** 主键*/private int id;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 保留字段*/private String reserve;/*** 保留字段1*/private int reserve1;/*** 角色集合*/private List<Role> roleList = new ArrayList<>();public User(String json) throws IOException {User user = new ObjectMapper().readValue(json,User.class);this.id = user.getId();this.username = user.getUsername();this.password = user.getPassword();this.reserve = user.getReserve();this.reserve1 = user.getReserve1();this.roleList = user.getRoleList();}
}
2、com/example/demo/entity/Role.java
package com.example.demo.entity;import lombok.*;import java.util.ArrayList;
import java.util.List;@Data
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Role {/*** 主键*/private int id;/*** 角色名称*/private String name;/*** 角色描述*/private String description;/*** 权限集合*/private List<Permission> permissionList=new ArrayList<>();}
3、com/example/demo/entity/Permission.java
package com.example.demo.entity;import lombok.*;@Data
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Permission {/*** 主键*/private int id;/*** 权限名称*/private String name;/*** 权限描述*/private String description;}
前后端分离项目中使用shiro的session鉴别用户身份
1、src/main/resources/static/index.html
<template id="sign"><div class="handle"><div class="handle-input"><div class="high70"><span>用户名称:</span><el-inputv-model="username"placeholder="请输入用户名称"clearable></el-input></div><div class="high70"><span>密码:</span><el-inputv-model="password"placeholder="请输入密码"clearableshow-password></el-input></div><el-button @click="login" plain>登录</el-button></div></div>
</template>
login() {axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/login',data: JSON.stringify({username: this.username,password: this.password})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){this.username = '';this.password = '';ELEMENT.Notification.error({title: '登录失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}this.permissionsStr = response.data.permissions;this.token = response.data.token;this.$router.push({name: 'manager',params: {token: this.token,permissionsStr: this.permissionsStr}});}).catch(error => {console.log(error);ELEMENT.Message(error);});}
2、com/example/demo/controller/UserCtrl.java
/*** 登录接口** @param user user* @return resultMap*/@RequestMapping(value = "/login", method = RequestMethod.POST)public Map<String, Object> login(@RequestBody User user) {//拿到主体Subject subject = SecurityUtils.getSubject();try {UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword());subject.login(usernamePasswordToken);Object permissions = subject.getSession().getAttribute("permissions");subject.getSession().removeAttribute("permissions");return userService.resultMap("permissions", permissions, "token", subject.getSession().getId(), "", "");}catch (Exception e){e.printStackTrace();return userService.resultMap("error", e.getMessage(), "", "", "", "");}}
3、com/example/demo/config/UserRealm.java
/*** 认证* @param authenticationToken* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//从token中获取用户信息String uesrName = (String) authenticationToken.getPrincipal();User user = userService.findUserByName(uesrName);if (user == null) {return null;}//权限集合Set<String> stringPermissionSet = new HashSet<>();user.getRoleList().forEach(role -> {stringPermissionSet.addAll(role.getPermissionList().stream().map(Permission::getName).collect(Collectors.toList()));});SecurityUtils.getSubject().getSession().setAttribute("permissions", stringPermissionSet);//密码String pwd = user.getPassword();if (pwd == null || "".equals(pwd)) {return null;}return new SimpleAuthenticationInfo(uesrName, pwd, this.getClass().getName());}
4、com/example/demo/service/UserService.java
public User findUserByName(String userName) {User user = userMapper.findUserByName(userName);//用户角色的集合List<Role> roleList = roleMapper.findRoleListByUserId(user.getId());user.setRoleList(roleList);return user;}
5、src/main/resources/mapper/UserMapper.xml
<resultMap id="resultUser" type="com.example.demo.entity.User"><result property="id" column="id" /><result property="username" column="username" /><result property="password" column="password" /></resultMap><select id="findUserByName" resultMap="resultUser" parameterType="String">selectid,username,passwordfrom user whereusername = #{userName}</select>
6、src/main/resources/mapper/RoleMapper.xml
<resultMap id="roleResult" type="com.example.demo.entity.Role"><result property="id" column="id" /><result property="name" column="name" /><result property="description" column="description" /><collection property="permissionList" column="id" select="com.example.demo.mapper.PermissionMapper.findByPermissionListByRoleId" /></resultMap><resultMap id="roleResultNotPermission" type="com.example.demo.entity.Role"><result property="id" column="id" /><result property="name" column="name" /><result property="description" column="description" /></resultMap><select id="findRoleListByUserId" resultMap="roleResult" parameterType="int">selectr.id id,r.name name,r.description descriptionfromuser_role urleft join role r onur.role_id = r.idwhereur.user_id = #{userId}</select>
7、src/main/resources/mapper/PermissionMapper.xml
<resultMap id="permissionResult" type="com.example.demo.entity.Permission"><result property="id" column="id" /><result property="name" column="name" /><result property="description" column="description" /></resultMap><select id="findByPermissionListByRoleId" resultMap="permissionResult" parameterType="int">selectp.id id,p.name name,p.description descriptionfromrole_permission rpleft join permission p onrp.permission_id = p.idwhererp.role_id = #{roleId}</select>
8、页面
9、src/main/resources/static/index.html
queryPermissionList() {axios.defaults.headers.token = this.token;axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';axios({method: 'post',url: '/user/findPermissionListByRoleId',data: JSON.stringify({id: 0})}).then(response => {if(typeof response.data.error !== 'undefined' || response.data.error != null){ELEMENT.Notification.error({title: '查询失败!',message: response.data.error,position: 'top-right',showClose: false,offset: 110});return;}this.permissionData = response.data.allPermissionList;}).catch(error => {console.log(error);ELEMENT.Message(error);});},
10、com/example/demo/config/UserSessionManager.java
package com.example.demo.config;import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;public class UserSessionManager extends DefaultWebSessionManager {public static final String AUTHORIZATION="token";public UserSessionManager() {super();}@Overrideprotected Serializable getSessionId(ServletRequest request, ServletResponse response) {//获取sessionIdString sessionId= WebUtils.toHttp(request).getHeader(AUTHORIZATION);if (sessionId!=null && sessionId!=""){request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);return sessionId;}else {return super.getSessionId(request,response);}}}
11、参考链接:
https://blog.csdn.net/qq_25046827/article/details/124540457
https://blog.csdn.net/palerock/article/details/73457415
前端控制按钮显隐,后端请求路径拦截配置
用户登陆成功后会返回用户具有的权限列表,根据权限列表控制前端控制按钮显隐及后端请求拦截路径,
总结如下:
相关代码
com/example/demo/config/ShiroConfig.java
package com.example.demo.config;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap;
import java.util.Map;@Configuration
public class ShiroConfig {@Beanpublic ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {System.out.println("ShiroConfig ShiroFilterFactoryBean 执行");ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//设置SecurityManagershiroFilterFactoryBean.setSecurityManager(securityManager);//如果访问需要登录的某个接口,却没有登录,则调用此接口(如果不是前后端分离,则跳转页面)//shiroFilterFactoryBean.setLoginUrl("/index.html");//登录成功后,跳转的链接,若前后端分离,没必要设置这个//shiroFilterFactoryBean.setSuccessUrl("");//登录成功,未授权会调用此方法//shiroFilterFactoryBean.setUnauthorizedUrl("/user/*");//拦截路径,必须使用:LinkedHashMap,要不然拦截效果会时有时无,因为使用的是无序的MapMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();//key=正则表达式路径,value=org.apache.shiro.web.filter.mgt.DefaultFilter//退出过滤器//filterChainDefinitionMap.put("/logout", "logout");//匿名可以访问,游客模式filterChainDefinitionMap.put("/", "anon");filterChainDefinitionMap.put("/user/login", "anon");//登录用户才可以访问filterChainDefinitionMap.put("/user/**", "authc");//管理员角色才能访问//filterChainDefinitionMap.put("/user/**", "roles[admin]");//有权限才能访问filterChainDefinitionMap.put("/user/queryUserListPage", "perms[query_user, add_user, allot_roles, remove_user]");filterChainDefinitionMap.put("/user/insertUser", "perms[add_user]");filterChainDefinitionMap.put("/user/removeUser", "perms[remove_user]");filterChainDefinitionMap.put("/user/findRoleListByUserId", "perms[allot_roles, query_role, add_role, remove_role, allot_permission]");filterChainDefinitionMap.put("/user/updateUserRole", "perms[allot_roles]");filterChainDefinitionMap.put("/user/addRole", "perms[add_role]");filterChainDefinitionMap.put("/user/removeRole", "perms[remove_role]");filterChainDefinitionMap.put("/user/findPermissionListByRoleId", "perms[allot_permission]");filterChainDefinitionMap.put("/user/updateRolePermission", "perms[allot_permission]");//authc:url必须通过认证才可以访问//anon:url可以匿名访问//过滤链是顺序执行,从上而下,一般把/**,放到最下面filterChainDefinitionMap.put("/**", "authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}@Beanpublic SecurityManager securityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();//如果不是前后端分离,不用设置setSessionManagersecurityManager.setSessionManager(sessionManager());securityManager.setRealm(userRealm());return securityManager;}/*** 自定义realm** @return*/@Beanpublic UserRealm userRealm() {UserRealm userRealm = new UserRealm();//因为数据库密码存的是明文,所以无需使用双重md5校验
// customRealm.setCredentialsMatcher(hashedCredentialsMatcher());return userRealm;}/*** 密码验证器,双重md5** @return*/@Beanpublic HashedCredentialsMatcher hashedCredentialsMatcher() {HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();//设置散列算法,使用md5算法hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列次数,使用2次md5算法,相当于md5(md5(xxx))hashedCredentialsMatcher.setHashIterations(2);return hashedCredentialsMatcher;}/*** 自定义SessionManager** @return*/@Beanpublic SessionManager sessionManager() {UserSessionManager userSessionManager = new UserSessionManager();//超时时间,默认 30分钟,会话超时,单位毫秒
// customSessionManager.setGlobalSessionTimeout(200000);return userSessionManager;}
}
待完成
1、密码加解密;
2、记住我;
相关文章:
shiro、springboot、vue、elementUI CDN模式前后端分离的权限管理demo 附源码
shiro、springboot、vue、elementUI CDN模式前后端分离的权限管理demo 附源码 源码下载地址 https://github.com/Aizhuxueliang/springboot_shiro.git 前提你电脑的安装好这些工具:jdk8、idea、maven、git、mysql; shiro的主要概念 Shiro是一个强大…...
智能优化算法——粒子群优化算法(PSO)(小白也能看懂)
前言: 暑假期间,因科研需要,经常在论文中看到各种优化算法,所以自己学习了一些智能优化的算法,做了一些相关的纸质性笔记,寒假一看感觉又有点遗忘了,并且笔记不方便随时查看,所以希…...
Lesson 6.4 逻辑回归手动调参实验
文章目录一、数据准备与评估器构造1. 数据准备2. 构建机器学习流二、评估器训练与过拟合实验三、评估器的手动调参在补充了一系列关于正则化的基础理论以及 sklearn 中逻辑回归评估器的参数解释之后,接下来,我们尝试借助 sklearn 中的逻辑回归评估器&…...
Oracle数据库入门大全
oracle数据库 Oracle 数据库、实例、用户、表空间、表之间的关系 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSv0SArH-1675906973035)(vx_images/573695710268888.png 676x)] 数据库 数据库是数据集合。Oracle是一种数据库管理系统ÿ…...
C语言操作符详解(下)
提示:本篇内容是C语言操作符详解下篇 文章目录前言八、条件表达式九、逗号表达式十、 下标引用、函数调用和结构成员1. [ ] 下标引用操作符2. ( ) 函数调用操作符3.结构成员访问操作符十一、表达式求值1. 隐式类型转换举例说明1举例说明2举例说明32.算数转换3.操作…...
【五六七人口普查】我国省市两级家庭户住房状况
人口数据是我们在各项研究中最常使用的数据!之前我们分享过第七次人口普查(简称七普)的数据!很多小伙伴拿到数据后都反馈数据非常好用,同时很多小伙伴咨询有没有前面几次人口普查的数据,这样方便做人口变化…...
大数据框架之Hadoop:入门(二)从Hadoop框架讨论大数据生态
第2章 从Hadoop框架讨论大数据生态 2.1 Hadoop是什么 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。主要解决,海量数据的存储和海量数据的分析计算问题。广义上来说,Hadoop通常是指一个更广泛的概念-Hadoop生态圈。 2.2 Hadoop发展历史 1&…...
负载均衡反向代理下的webshell上传+apache漏洞
目录一、负载均衡反向代理下的webshell上传1、nginx 负载均衡2、搭建环境3、负载均衡下的 WebShell连接的难点总结难点一、需要在每一台节点的相同位置都上传相同内容的 WebShell难点二、无法预测下次的请求交给哪台机器去执行。难点三、下载文件时,可能会出现飘逸&…...
打造安全可信的通信服务,阿里云云通信发布《短信服务安全白皮书》
随着数字化经济的发展,信息保护和数据安全成为企业、个人关注的焦点。近日,阿里云云通信发布《短信服务安全白皮书》,该白皮书包含安全责任共担、安全合规、安全架构三大板块,呈现了阿里云云通信在信息安全保护方面的技术能力、安…...
Python项目实战——外汇牌价(附源码)
前言 几乎每个人都在使用银行卡,今天我们就来爬取某行外汇牌价,获取我们想要的数据。 环境使用 python 3.9pycharm 模块使用 requests 模块介绍 requestsrequests是一个很实用的Python HTTP客户端库,爬虫和测试服务器响应数据时经常会用到&…...
String、StringBuffer、StringBuilder有什么区别?
第5讲 | String、StringBuffer、StringBuilder有什么区别? 今天我会聊聊日常使用的字符串,别看它似乎很简单,但其实字符串几乎在所有编程语言里都是个特殊的存在,因为不管是数量还是体积,字符串都是大多数应用中的重要…...
python基于django+vue的高铁地铁火车订票管理系统
目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发环境 4 2.1 使用工具简介 4 2.2 环境配置 4 2.4 MySQL数据库 5 2.5 框架介绍 5 3 系统分析 6 3.1系统可行性分析 6 3.1.1经济可行性 6 3.1.2技术可行性 6 3.1.3运行可…...
全栈自动化测试技术笔记(一):前期调研怎么做
昨天下午在家整理书架,把很多看完的书清理打包好,预约了公益捐赠机构上门回收。 整理的过程中无意翻出了几年前的工作记事本,里面记录了很多我刚开始做自动化和性能测试时的笔记。 虽然站在现在的角度来看,那个时候无论是技术细…...
专家培养计划
1、先知道一百个关键词 进入一个行业,如果能快速掌握其行业关键词,你会发现,你和专家的距离在迅速缩短。 若不然,可能同事间的日常交流,你都会听得云里雾里,不知所云。 比如做零售,就要了解零售…...
583. 两个字符串的删除操作 72. 编辑距离
583. 两个字符串的删除操作 dp[i][j]:以i-1结尾的word1和j-1结尾的word2 变成相同字符串最少的步骤为dp[i][j] 初始化dp[i][0],dp[0][j]为空字符串和第一个字符匹配的最少步骤,即i/j,删除对应的字符个数。dp[i][0]i,dp[0][j]j; 遍历两个字符串。 若word1…...
[多线程进阶] 常见锁策略
专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录: 1. 常见的锁策略 1.1 乐观锁 vs 悲观锁 1.2 读写…...
Scala - Idea 项目报错 Cannot resolve symbol XXX
一.引言 Idea 编译 Scala 项目大面积报错 Cannot resolve symbol xxx。 二.Cannot resolve symbol xxx 1.问题描述 Idea 内的 Scala 工程打开后显示下述异常: 即 Scala 常规语法全部失效,代码出现大面积红色报错。 2.尝试解决方法 A.设置 Main Sourc…...
信息化发展与应用的新特点
一、信息化发展与应用二、国家信息化发展战略三、电子政务※四、电子商务五、两化融合(工业和信息化)六、智慧城市 一、信息化发展与应用 我国在“十三五”规划纲要中,将培育人工智能、移动智能终端、第五代移动通信(5G)先进传感器等作为新…...
软件测试】测试时间不够了,我很慌?项目马上发布了......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 常见的几种情况&…...
MapReduce编程规范
MapReduce编程规范 MapReduce的开发一共有八个步骤,其中Map阶段分为2个步骤,Shuffle阶段4个步骤,Reduce阶段分为2个步骤。 Map阶段2个步骤 设置InputFormat类,将数据切分为Key-Value(K1和V1)对,输入到第二步。 自定义Map逻辑,将第一步的结果转换成另外的…...
Unity 如何实现游戏Avatar角色头部跟随视角转动
文章目录功能简介实现步骤获取看向的位置获取头部的位置修改头部的朝向限制旋转角度超出限制范围时自动回正如何让指定动画不受影响功能简介 如图所示,当相机的视角转动时,Avatar角色的头部会同步转动,看向视角的方向。 实现步骤 获取看向的…...
深度学习优化算法总结
深度学习的优化算法 优化的目标 优化提供了一种最大程度减少深度学习损失函数的方法,但本质上,优化和深度学习的目标不同。 优化关注的是最小化目标;深度学习是在给定有限数据量的情况下寻找合适的模型。 优化算法 gradient descent…...
CMake详细使用
1、CMake简介CMake是一个用于管理源代码的跨平台构建工具可以方便地根据目标平台和编译工具产生对应的编译文件主要用于C/C语言的构建,但是也可以用于其它编程语言的源代码。如同使用make命令工具解析Makefile文件一样cmake命令工具依赖于一个CMakeLists.txt的文件该…...
【数据结构与算法】前缀树的实现
🌠作者:阿亮joy. 🎆专栏:《数据结构与算法要啸着学》 🎇座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉…...
canvas 制作2048
效果展示 对UI不满意可以自行调整,这里只是说一下游戏的逻辑,具体的API调用不做过多展示。 玩法分析 2048 的玩法非常简单,通过键盘的按下,所有的数字都向着同一个方向移动,如果出现两个相同的数字,就将…...
playwright: 全局修改页面等待超时时间
等待超时时间默认是30s, 可以通过以下几个方法设置: browser_context.set_default_navigation_timeout()browser_context.set_default_timeout()page.set_default_navigation_timeout()page.set_default_timeout() set_default_navigation_timeout set_default_n…...
C++类和对象(中)
✨个人主页: Yohifo 🎉所属专栏: C修行之路 🎊每篇一句: 图片来源 I do not believe in taking the right decision. I take a decision and make it right. 我不相信什么正确的决定。我都是先做决定,然后把…...
Docker安装EalasticSearch、Kibana,安装Elasticvue插件
使用Docker快速安装部署ES和Kibana的前提:首先需要确保已经安装了Docker环境。 如果没有安装Docker的话,先在Linux上安装Docker。 有了Docker环境后,就可以使用Docker安装部署ES和Kibana了 一、安装ES 1、拉取EalasticSearch镜像 docker p…...
算法训练营 day39 贪心算法 无重叠区间 划分字母区间 合并区间
算法训练营 day39 贪心算法 无重叠区间 划分字母区间 合并区间 无重叠区间 435. 无重叠区间 - 力扣(LeetCode) 给定一个区间的集合 intervals ,其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互…...
c/c++开发,无可避免的文件访问开发案例
一、缓存文件系统 ANSI C标准中的C语言库提供了fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等标准函数,这些函数在不同的操作系统中应该调用不同的内核API,从而支持开发者跨平台实现对文件的访问。 在Lin…...
买完域名后如何建设网站/企业网站建设要多少钱
在Sqlserver的维护更新操作中,有时候涉及到Update操作,其中有一种情况是根据特定的条件,以一个表中的数据更新另一个表的数据,此时涉及到两个表之间的关系以及操作,此处介绍2种更新方法。(1)方法…...
苏州网站制作好的公司/厦门人才网官网登录
《1.1.1什么是计算机网络》由会员分享,可在线阅读,更多相关《1.1.1什么是计算机网络(9页珍藏版)》请在人人文库网上搜索。1、认识计算机网络,一、计算机网络的定义,计算机网络是一种地理上分散、具有独立功的各台计算机通过软、硬件设备互连,…...
srcache缓存wordpress/网站站点查询
点击上方“Java基基”,选择“设为星标”做积极的人,而不是积极废人!每天 14:00 更新文章,每天掉亿点点头发...源码精品专栏 原创 | Java 2021 超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框…...
越秀建设网站/成人用品网店进货渠道
图片来源:Vimeo 现在做移动应用的技术下限真是越来越低了,未来说不定会出现这样的应用:通过语音告诉该应用我想要一个什么样的应用,然后程序就自动生成一个符合要求的应用出来。当然这个想的有点远了,我们先来看点实际…...
flash网站建设方案/友情链接平台网站
66_elasticSearch 基于nested object实现博客与评论嵌套关系 更多干货 分布式实战(干货)spring cloud 实战(干货)mybatis 实战(干货)spring boot 实战(干货)React 入门实战ÿ…...
web网站开发公司/互联网优化是什么意思
删除第一个字符串当中出现的第二个字符串中的字符 例如; String s1"welcome to bit"; String s2"come";输出: “wl t bit”; 思路: 拿着s1的字符每个字符,看s2中是否包含这个字符,若不包含则将这…...