1.项目基础
 2.定义统一返回结果对象
 3.Nodejs
 4.前端内容编写
 5.菜单详情
 6.SpringSecurity权限管理
 7.添加登录日志
 8.操作日志
 9.后端打包
 10.前端打包
 11.动态sql日期的判断
项目基础

  
    定义统一返回结果对象
  
 
 - 定义全局统一返回结果类
import lombok.Data;
/**
 * 全局统一返回结果类
 *
 */
@Data
public class Result<T> {
    //返回码
    private Integer code;
    //返回消息
    private String message;
    //返回数据
    private T data;
    public Result(){}
    // 返回数据
    protected static <T> Result<T> build(T data) {
        Result<T> result = new Result<T>();
        if (data != null)
            result.setData(data);
        return result;
    }
    public static <T> Result<T> build(T body, Integer code, String message) {
        Result<T> result = build(body);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }
    public static<T> Result<T> ok(){
        return Result.ok(null);
    }
    /**
     * 操作成功
     * @param data  baseCategory1List
     * @param <T>
     * @return
     */
    public static<T> Result<T> ok(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }
    public static<T> Result<T> fail(){
        return Result.fail(null);
    }
    /**
     * 操作失败
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> fail(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }
    public Result<T> message(String msg){
        this.setMessage(msg);
        return this;
    }
    public Result<T> code(Integer code){
        this.setCode(code);
        return this;
    }
}
- 定义统一返回结果状态信息类
import lombok.Getter;
/**
 * 统一返回结果状态信息类
 *
 */
@Getter
public enum ResultCodeEnum {
    SUCCESS(200,"成功"),
    FAIL(201, "失败"),
    SERVICE_ERROR(2012, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    ILLEGAL_REQUEST(205, "非法请求"),
    REPEAT_SUBMIT(206, "重复提交"),
    ARGUMENT_VALID_ERROR(210, "参数校验异常"),
    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),
    ACCOUNT_ERROR(214, "账号不正确"),
    PASSWORD_ERROR(215, "密码不正确"),
    LOGIN_MOBLE_ERROR( 216, "账号不正确"),
    ACCOUNT_STOP( 217, "账号已停用"),
    NODE_ERROR( 218, "该节点下有子节点,不可以删除")
    ;
    private Integer code;
    private String message;
    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
- 编写controller,返回对象

Node.js

NPM 构建前端项目-管理依赖

模块化开发
-  设置方法,设置那些方法可以被其他js调用 
  
-  引入js文件,调用其方法 
  
ES6写法
- 定义方法,加上export关键字
  
- import 的方式 只取需要的方法即可,多个方法用逗号分隔
  
- 需要进行转码 将自己转为es5 babel 文件 -d 转后的文件名称
  
es6 的第二种写法
- 定义方法
 2. 调用方法
2. 调用方法
 
 3. 进行转码操作,运行操作
 babel es6-2 -d es5-2
 babel-node --presets env 2.js
 npm run dev
vue修改访问本地端口

 
 
角色列表的实现
- 添加角色管理路由
  
角色开发 创建路由 创建页面


2.Api定义接口

 

3.调用api方法,获取响应的数据

 
4.把接口返回的数据进行处理
查询

 列表
 
3. 分页

4. 列表删除

新增方法

修改方法

批量删除

<template>
  <div class="app-container">
    角色列表
    <!--查询表单-->
    <div class="search-div">
      <el-form label-width="70px" size="small">
        <el-row>
          <el-col :span="24">
            <el-form-item label="角色名称">
              <el-input style="width: 100%" v-model="searchObj.roleName" placeholder="角色名称"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row style="display:flex">
          <el-button type="primary" icon="el-icon-search" size="mini"  @click="fetchData()">搜索</el-button>
          <el-button icon="el-icon-refresh" size="mini" @click="resetData">重置</el-button>
        </el-row>
      </el-form>
    </div>
    <!-- 工具条 -->
  <div class="tools-div">
    <el-button type="success" icon="el-icon-plus" size="mini" @click="add">添 加</el-button>
    <el-button class="btn-add" size="mini" @click="batchRemove()" >批量删除</el-button>
  </div>
    <!-- 表格  listLoading 页面加载转圈效果   :data="list" -- list 每页的列表数据    -->
    <el-table
      v-loading="listLoading"
      :data="list"           
      stripe
      border
      style="width: 100%;margin-top: 10px;"
      @selection-change="handleSelectionChange">// 改变复选框就会触发条件 
      <el-table-column type="selection"/>  // table 组件上添加复选框
      
      <el-table-column
        label="序号"
        width="70"
        align="center">
        <template slot-scope="scope">
          {{ (page - 1) * limit + scope.$index + 1 }}
        </template>
      </el-table-column>
      <el-table-column prop="roleName" label="角色名称" />
      <el-table-column prop="roleCode" label="角色编码" />
      <el-table-column prop="createTime" label="创建时间" width="160"/>
      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
          <el-button type="primary" icon="el-icon-edit" size="mini" @click="edit(scope.row.id)" title="修改"/>
          <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeDataById(scope.row.id)" title="删除"/>
          <el-button type="warning" icon="el-icon-baseball" size="mini" @click="showAssignAuth(scope.row)" title="分配权限"/>
        </template>
      </el-table-column>
    </el-table>
  <!-- 分页组件 -->
    <el-pagination
      :current-page="page"
      :total="total"
      :page-size="limit"
      style="padding: 30px 0; text-align: center;"
      layout="total, prev, pager, next, jumper"
      @current-change="fetchData"
    />
    <el-dialog title="添加/修改" :visible.sync="dialogVisible" width="40%" >
          <el-form ref="dataForm" :model="sysRole" label-width="150px" size="small" style="padding-right: 40px;">
            <el-form-item label="角色名称">
              <el-input v-model="sysRole.roleName"/>
            </el-form-item>
            <el-form-item label="角色编码">
              <el-input v-model="sysRole.roleCode"/>
            </el-form-item>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false" size="small" icon="el-icon-refresh-right">取 消</el-button>
            <el-button type="primary" icon="el-icon-check" @click="saveOrUpdate()" size="small">确 定</el-button>
          </span>
    </el-dialog>
  </div>
</template>
<script>
//引入定义接口的js文件
import api from '@/api/system/role'
export default {
  //定义初始值/初始变量
  data() {
    return {
      listLoading:false,//是否显示加载
      list:[],//角色列表
      total:0,//总记录数
      page:1,//当前页
      limit:3,//每页显示记录数
      
      searchObj:{},//条件查询封装对象
      dialogVisible: false,//弹出框
      sysRole:{}, //封装添加表单数据
      selectValue:[] //复选框选择内容封装数组
    }
  },
  //页面渲染之前执行
  created() {
    //调用列表方法
    this.fetchData()
  },
  methods:{//具体方法
    //跳转分配菜单权限
    showAssignAuth(row) {
      this.$router.push('/system/assignAuth?id='+row.id+'&roleName='+row.roleName);
    },
    //复选框发生变化执行方法
    handleSelectionChange(selection) {
      this.selectValue = selection
      //console.log(this.selectValue)
    },
    //批量删除
    batchRemove() {
      //判断
      if(this.selectValue.length==0) {
        this.$message.warning('请选择要删除的记录!')
        return
      }
      this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          //数组
          var idList = []
          //获取多个复选框对应id,封装到数组里面
          // [1,2,3]
          for(var i=0;i<this.selectValue.length;i++) {
            var obj = this.selectValue[i]
            //id值
            var id = obj.id
            //放到数组里面
            idList.push(id)
          }
          api.batchRemove(idList).then(response => {
              //提示
              this.$message({
                type: 'success',
                message: '删除成功!'
              });
              //刷新
              this.fetchData()
          })
        })
    },
    //修改-数据回显
    edit(id) {
      //弹出框
      this.dialogVisible = true
      api.getRoleId(id).then(response => {
        this.sysRole = response.data
      })
    },
    //点击确定
    saveOrUpdate() {
      //判断添加还是修改
      if(!this.sysRole.id) {
        //添加
        this.saveRole()
      } else {
        this.updateRole()
      }
    },
    //修改的方法
    updateRole() {
      api.update(this.sysRole)
        .then(response => {
          //提示
          this.$message({
            type: 'success',
            message: '修改成功!'
          });
          //关闭弹框
          this.dialogVisible = false
          //刷新页面
          this.fetchData()
        })
    },
    //添加的方法
    saveRole() {
      api.saveRole(this.sysRole)
        .then(response => {
          //提示
          this.$message({
            type: 'success',
            message: '添加成功!'
          });
          //关闭弹框
          this.dialogVisible = false
          //刷新页面
          this.fetchData()
        })
    },
    //点击添加,弹出框
    add() {
      this.dialogVisible = true
      this.sysRole = {}
    },
    //删除
    removeDataById(id) {
       this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          //调用方法删除
          api.removeId(id)
            .then(response => {
              //提示
              this.$message({
                type: 'success',
                message: '删除成功!'
              });
              //刷新
              this.fetchData()
          })
        })
    },
    //重置
    resetData() {
      //清空表单
      this.searchObj = {}
      //查询所有数据
      this.fetchData()
    },
    //条件分页查询列表
    //pageNum 查询页数
    fetchData(pageNum=1) {
      //页数赋值
      this.page = pageNum
      //ajax
      api.getPageList(this.page,this.limit,this.searchObj)
        .then(response => {      // 调用接口成功执行then方法
          //this.listLoading = false
          //console.log(response)
          //每页数据列表
          this.list = response.data.records
          //总记录数
          this.total = response.data.total
        })
    }
  }
}
</script>
api
import request from '@/utils/request'
//常量
const api_name = '/admin/system/sysUser'
export default {
    //列表
    getPageList(page,limit,searchObj) {
        return request({
            //接口路径
            url: `${api_name}/${page}/${limit}`,
            method: 'get', //提交方式
            //参数
            params: searchObj
        })
    },
    //添加
    save(user) {
        return request({
            //接口路径
            url: `${api_name}/save`,
            method: 'post', //提交方式
            //参数
            data: user
        })
    },
    //根据id查询
    getUserId(id) {
        return request({
            //接口路径
            url: `${api_name}/getUser/${id}`,
            method: 'get' //提交方式
        })
    },
    //修改
    update(user) {
        return request({
            //接口路径
            url: `${api_name}/update`,
            method: 'post', //提交方式
            //参数
            data: user  // 将结果转为list进行传递
        })
    },
    //删除
    removeById(id) {
        return request({
            //接口路径
            url: `${api_name}/remove/${id}`,
            method: 'delete' //提交方式
        })
    },
    //更改用户状态
    updateStatus(id,status) {
        return request({
            //接口路径
            url: `${api_name}/updateStatus/${id}/${status}`,
            method: 'get' //提交方式
        })
    },
}
禁用启用

 //更改用户状态
    switchStatus(row) {
      //判断,如果当前用户可用,修改禁用
      row.status = row.status === 1 ? 0 : 1
      api.updateStatus(row.id,row.status)
        .then(response => {
          this.$message.success(response.message || '操作成功')
          this.fetchData()
        })
    },
 <el-table-column prop="username" label="用户名" width="180"/>
      <el-table-column prop="name" label="姓名" width="110"/>
      <el-table-column prop="phone" label="手机" />
      <el-table-column label="状态" width="80">
        <template slot-scope="scope">
          <el-switch
            v-model="scope.row.status===1"
            @change="switchStatus(scope.row)">
          </el-switch>
        </template>
      </el-table-column>
 //更改用户状态
    updateStatus(id,status) {
        return request({
            //接口路径
            url: `${api_name}/updateStatus/${id}/${status}`,
            method: 'get' //提交方式
        })
    },
  
    菜单管理
  
 
 
 
代码实现
当前节点下存在子节点使用递归的方式
 

import com.qwq.model.system.SysMenu;
import java.util.ArrayList;
import java.util.List;
public class MenuHelper {
    // 构建树形结构
    public static List<SysMenu> bulidTree(List<SysMenu> list) {
        List<SysMenu> trees = new ArrayList<>();
        for (SysMenu sysMenu : list) {
             //先得到根节点进行遍历
            if (sysMenu.getParentId().longValue() == 0) {
                trees.add(findChildren(sysMenu,list));
            }
        }
        return trees;
    }
    /**
     * 递归查找子节点
     * @param treeNodes
     * @return
     */
    public static SysMenu findChildren(SysMenu sysMenu, List<SysMenu> treeNodes) {
        sysMenu.setChildren(new ArrayList<SysMenu>());
        // sysMenu = 根节点    treeNodes = 全部数据集合
        //  遍历全部数据
        for (SysMenu it : treeNodes) {
            String id = sysMenu.getId();
            long ids = Long.parseLong(id);
            // 全部数据的ParentId
            Long parentId = it.getParentId();
            //  根节点 id == 遍历数据的parentId
            //  2 == 3  3 == 6
            if (ids == parentId) {
                System.out.println(ids +"============"+ it.getId());
                sysMenu.getChildren().add(findChildren(it ,  treeNodes));
            }
        }
        return sysMenu;
    }
}
  
    权限管理
  
 
 关于安全方面的两个核心功能是“认证”和“授权”,一般来说,Web 应用的安全性包括**用户认证(Authentication)和用户授权(Authorization)**两个部分,这两点也是 SpringSecurity 重要核心功能。
(1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码来完成认证过程。
通俗点说就是系统认为用户是否能登录
(2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
通俗点讲就是系统判断用户是否有权限去做某些事情。
用户认证流程

添加登录日志
验证登录的拦截器登录成功后,调用service , request转化为ip , 进行新增处理
 
public class IpUtil {
    public static String getIpAddress(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress="";
        }
        // ipAddress = this.getRequest().getRemoteAddr();
        return ipAddress;
    }
    public static String getGatwayIpAddress(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        return ip;
    }
}
  
    操作日志
  
 
 
  
    后端打包
  
 
 pom文件新增build标签
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

<div id = ‘10’ / > 前端打包

 输入命令进行打包
 
 
  
    日期
  
 
 格式:
<!--mapper的全限定类名-->
<mapper namespace="com.qwq.system.mapper.SysMenuMapper">
    <resultMap id="sysMenuMap" type="com.qwq.model.system.SysMenu" autoMapping="true">
    </resultMap>
    <!-- 用于select查询公用抽取的列 -->
    <sql id="columns">
      m.id,m.parent_id,m.name,m.type,m.path,m.component,m.perms,m.icon,m.sort_value,m.status,m.create_time,m.update_time,m.is_deleted
   </sql>
    <select id="findListByUserId" resultMap="sysMenuMap">
        select
        distinct <include refid="columns" />
        from sys_menu m
        inner join sys_role_menu rm on rm.menu_id = m.id
        inner join sys_user_role ur on ur.role_id = rm.role_id
        where
        ur.user_id = #{userId}
        and m.status = 1
        and rm.is_deleted = 0
        and ur.is_deleted = 0
        and  m.is_deleted = 0
    </select>
</mapper>

mybatis-plus的操作




![[ACTF2020 新生赛]BackupFile](https://img-blog.csdnimg.cn/99feb41cbba443619381475a3fb64a6d.png)














