SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—二歉提、日志、接口文檔等實現(xiàn)

目錄

SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—一区转、項目簡介和開發(fā)環(huán)境準備
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—二苔巨、日志、接口文檔等實現(xiàn)
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—三废离、主要頁面及接口實現(xiàn)
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—四侄泽、整合SpringSecurity(上)
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—五、整合SpringSecurity(下)
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—六厅缺、SpringSecurity整合jwt
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—七蔬顾、處理一些問題
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—八、AOP記錄用戶湘捎、異常日志
SpringSecurity權(quán)限管理系統(tǒng)實戰(zhàn)—九诀豁、數(shù)據(jù)權(quán)限的配置

前言

?本篇文章的內(nèi)容有點雜,搞得我都不知道怎么取標題了窥妇。

?上次我們已經(jīng)搭建好了my-springsecurity-plus的基本環(huán)境舷胜,本次我們我們要實現(xiàn)功能有系統(tǒng)日志配置、配置swagger接口文檔活翩、配置druid連接池等

一烹骨、Banner替換

?可以有些第一次接觸到這個名詞的小伙伴不清楚banner是什么,其實就是在運行springboot項目時控制臺打印出的圖案材泄,就是下面這個東西沮焕。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.1.RELEASE)

?這下是不是就熟悉了,其實SpringBoot支持自定義banner圖案拉宗。只需要放在指定位置峦树,SpringBoot會幫我們自動替換。Spring Boot 默認尋找 Banner 的順序是:

  1. 依次在 Classpath 下找 文件 banner.gif , banner.jpg , 和 banner.png , 先找到誰就用誰旦事。
  2. 繼續(xù) Classpath 下找 banner.txt
  3. 上面都沒有找到的話, 用默認的 SpringBootBanner

我們只需要在 src/main/resources 下新建一個 banner.txt魁巩,然后找一個在線生成banner的網(wǎng)站,例如patorjk姐浮,然后將生成的文本復(fù)制到banner.txt文件中谷遂。啟動項目,查看控制臺

bash.png

是不是很炫酷卖鲤,一個知名項目的banner是這樣的

////////////////////////////////////////////////////////////////////
//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//            佛祖保佑       永不宕機     永無BUG                    //
////////////////////////////////////////////////////////////////////

二肾扰、日志

?在項目的開發(fā)中畴嘶,日志是必不可少的一個記錄事件的組件。應(yīng)該很多不少剛?cè)腴T的小伙伴對日志都是不怎么重視集晚,對于我來說也是這樣掠廓,即使現(xiàn)在我對日志也不是很重視,也沒有養(yǎng)成記錄日志的習(xí)慣甩恼。但其實日志在一個系統(tǒng)中尤為的重要,可以幫助快速定位bug沉颂,來保證服務(wù)的高可用条摸。

?Spring Boot默認使用LogBack日志系統(tǒng),如果不需要更改為其他日志系統(tǒng)如Log4j2等铸屉,則無需多余的配置钉蒲,LogBack默認將日志打印到控制臺上。

?而Spring Boot項目一般都會引用spring-boot-starter或者spring-boot-starter-web的依賴彻坛,這兩個依賴中包含了spring-boot-starter-logging的依賴顷啼,所以我們?nèi)绻皇褂脛e的日志框架,無需修改依賴昌屉。

?如果我們要使用日志功能钙蒙,只需要在相應(yīng)類上加上@Slf4j(需要lambok插件)注解,在對應(yīng)方法中l(wèi)og.indf(),log.error()等就可以輸出日志间驮。我們把HelloController改造成如下這樣

@Controller
@Slf4j
public class HelloController {

    @GetMapping(value = "/index")
    public String index(){
        log.info("測試");
        log.error("測試");
        return "index";
    }   
    @GetMapping(value = "/login")
    public String login(){
        return "login";
    }
    @GetMapping(value = "/console/console1")
    public String console1(){
        return "console/console1";
    }
}

?重啟項目躬厌,訪問http://localhost:8080/index控制臺會打印如下信息

[圖片上傳失敗...(image-71d4c4-1596631367901)]

?那么如何把日志存貯到文件里呢?我們只要在application.yml中簡單定義一下

logging:
  file:
    path: src\main\resources\logger\ # logger文件夾需要提前生成

?啟動項目竞帽,會在logger目錄下生成一個spring.log文件扛施,內(nèi)容和控制臺輸出的一致。

?日志的輸出格式支持自定義屹篓,但是自定義后在控制臺輸出的內(nèi)容就不是彩色的了疙渣,當然也能定義成彩色的,還有日志文件生成的大卸亚伞(總不能一直存在一個文件里吧妄荔,那不就無限大了)和存儲時間等等,都可以自定義恳邀。我這里不詳細介紹了懦冰,有興趣的小伙伴可以自己了解。

三谣沸、Swagger接口文檔

?Swagger 是一個規(guī)范和完整的框架刷钢,用于生成、描述乳附、調(diào)用和可視化RESTful風格的 Web 服務(wù)内地“槌危總體目標是使客戶端和文件系統(tǒng)作為服務(wù)器以同樣的速度來更新。文件的方法阱缓,參數(shù)和模型緊密集成到服務(wù)器端的代碼非凌,允許API來始終保持同步。Swagger讓部署管理和使用功能強大的API變得非常簡單荆针。官方網(wǎng)站:http://swagger.io/敞嗡。
?Swagger也可以用來測試接口(很多人會用postman,但是swagger可能用起來更簡單一點)

?那么我們首先要在maven添加相關(guān)依賴

        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--swagger ui-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

? 這個我上一章給的依賴中有了航背,不要重復(fù)添加喉悴,這里只是為了說明。

? 在啟動類的那一層級中新建config包玖媚,在其中新建SwaggerConfig類

@Configuration//表明這是一個配置類
@EnableSwagger2//開啟Swagger
public class SwaggerConfig {
    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")//組名稱
                .apiInfo(webApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.codermy.myspringsecurityplus.controller"))//掃描的包
                .paths(PathSelectors.any())
                .build();

    }
    /**
     * 該套 API 說明箕肃,包含作者、簡介今魔、版本勺像、等信息
     * @return
     */
    private ApiInfo webApiInfo(){
        return new ApiInfoBuilder()
                .title("my-springsecurity-plus-API文檔")
                .description("本文檔描述了my-springsecurity-plus接口定義")
                .version("1.0")
                .build();
    }

}

? 然后我們訪問http://localhost:8080/swagger-ui.html

[圖片上傳中...(swagger.png-8efe91-1596544511585-0)]

? 接口的名字也可以自定義,詳細見Swagger 常用注解使用詳解

? 我們再改造一下HelloController

@Controller
@Slf4j
@Api(tags = "前期測試后面會刪")
public class HelloController {

    @GetMapping(value = "/index")
    public String index(){
        return "index";
    }

    @GetMapping(value = "/login")
    public String login(){
        return "login";
    }

    @GetMapping(value = "/console/console1")
    @ApiOperation(value = "轉(zhuǎn)發(fā)console1請求")
    public String console1(){
        return "console/console1";
    }
}

重啟訪問

api.png

四错森、主要界面接口

接下來我們把用戶管理吟宦,角色管理,和權(quán)限管理三個界面的的接口換成我們自己的涩维。

首先我們新建一個類來統(tǒng)一返回數(shù)據(jù)格式,新建utiils包督函,在其中新建Result類

//統(tǒng)一返回結(jié)果的類
@Data
public class Result<T> implements Serializable {

    @ApiModelProperty(value = "是否成功")
    private Boolean success;

    @ApiModelProperty(value = "返回碼")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String msg;

    @ApiModelProperty(value = "總數(shù)")
    private Integer count;

    @ApiModelProperty(value = "返回數(shù)據(jù)")
    private List<T> data = new ArrayList<T>();

    //把構(gòu)造方法私有
    private Result() {}

    public static Result table_sucess() {
        Result r = new Result();
        r.setSuccess(true);
        r.setCode(ResultCode.TABLE_SUCCESS);
        r.setMsg("成功");
        return r;
    }

    //成功靜態(tài)方法
    public static Result ok() {
        Result r = new Result();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMsg("成功");
        return r;
    }

    //失敗靜態(tài)方法
    public static Result error() {
        Result r = new Result();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMsg("失敗");
        return r;
    }
    public Result success(Boolean success){
        this.setSuccess(success);
        return this;
    }
    public Result message(String message){
        this.setMsg(message);
        return this;
    }
    public Result code(Integer code){
        this.setCode(code);
        return this;
    }

    public Result data(List<T> list){
        this.data.addAll(list);
        return this;
    }
    public Result count(Integer count){
        this.count = count;
        return this;
    }
}

在新建一個ReslutCode接口來定義常用的狀態(tài)碼

public interface ResultCode {
    /**
     * 請求t成功
     */
    public static Integer SUCCESS = 200;
    /**
     * 請求table成功
     */
    public static Integer TABLE_SUCCESS = 0;
    /**
     * 請求失敗
     */
    public static Integer ERROR = 201;

    /**
     * 請求已經(jīng)被接受
     */
    public static final Integer ACCEPTED = 202;

    /**
     * 操作已經(jīng)執(zhí)行成功,但是沒有返回數(shù)據(jù)
     */
    public static final Integer NO_CONTENT = 204;

    /**
     * 資源已被移除
     */
    public static final Integer MOVED_PERM = 301;

    /**
     * 重定向
     */
    public static final Integer SEE_OTHER = 303;

    /**
     * 資源沒有被修改
     */
    public static final Integer NOT_MODIFIED = 304;

    /**
     * 參數(shù)列表錯誤(缺少激挪,格式不匹配)
     */
    public static final Integer BAD_REQUEST = 400;

    /**
     * 未授權(quán)
     */
    public static final Integer UNAUTHORIZED = 401;

    /**
     * 訪問受限辰狡,授權(quán)過期
     */
    public static final Integer FORBIDDEN = 403;

    /**
     * 資源,服務(wù)未找到
     */
    public static final Integer NOT_FOUND = 404;

    /**
     * 不允許的http方法
     */
    public static final Integer BAD_METHOD = 405;

    /**
     * 資源沖突垄分,或者資源被鎖
     */
    public static final Integer CONFLICT = 409;

    /**
     * 不支持的數(shù)據(jù)宛篇,媒體類型
     */
    public static final Integer UNSUPPORTED_TYPE = 415;

    /**
     * 接口未實現(xiàn)
     */
    public static final Integer NOT_IMPLEMENTED = 501;
}

自定義異常處理(這里不過多解釋,只簡單實現(xiàn)直接貼代碼

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    //指定處理什么異常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e){
        e.printStackTrace();
        return Result.error().message("執(zhí)行了全局異常");
    }
    //自定義異常
    @ExceptionHandler(MyException.class)
    @ResponseBody
    public Result error(MyException e){
        log.error(e.getMessage());
        e.printStackTrace();
        return Result.error().code(e.getCode()).message(e.getMsg());
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyException extends  RuntimeException {
    private  Integer code;//狀態(tài)碼
    private String  msg;//異常信息
}

新建PageTableRequest 分頁工具類

@Data
public class PageTableRequest implements Serializable {

    private Integer page;//初始頁
    private Integer limit;//一頁幾條數(shù)據(jù)
    private Integer offset;//頁碼

    public void countOffset(){
        if(null == this.page || null == this.limit){
            this.offset = 0;
            return;
        }
        this.offset = (this.page - 1) * limit;
    }

}

下面進入正題

因為我這里用的是druid的連接池(之后介紹)薄湿,我直接把application.yml貼出來

server:
  port: 8080
spring:
  profiles:
    active: dev
  application:
    name: my-springsecurity-plus
  datasource:
    driver:
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 后面時區(qū)不要忘了如果你是mysql8.0以上的版本
    url: jdbc:mysql://localhost:3306/my-springsecurity-plus?serverTimezone=Asia/Shanghai
    username: root
    password: 180430121
    type: com.alibaba.druid.pool.DruidDataSource #druid連接池之后會解釋這里先復(fù)制
    druid:
      # 初始化配置
      initial-size: 3
      # 最小連接數(shù)
      min-idle: 3
      # 最大連接數(shù)
      max-active: 15
      # 獲取連接超時時間
      max-wait: 5000
      # 連接有效性檢測時間
      time-between-eviction-runs-millis: 90000
      # 最大空閑時間
      min-evictable-idle-time-millis: 1800000
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      validation-query: select 1
      # 配置監(jiān)控統(tǒng)計攔截的filters
      filters: stat
      web-stat-filter:
        url-pattern: /*
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
      #StatViewServlet配置叫倍,說明請參考Druid Wiki,配置_StatViewServlet配置
      stat-view-servlet:
        enabled: true #是否啟用StatViewServlet默認值true
        url-pattern: /druid/*
        reset-enable: true
        login-username: admin
        login-password: admin
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

# mybatis配置
mybatis:
  type-aliases-package: com.codermy.myspringsecurityplus.entity
  mapper-locations: classpath:/mybatis-mappers/*
  configuration:
    map-underscore-to-camel-case: true

logging:
  file:
    path: src\main\resources\logger\ # logger文件夾需要提前生成


用戶管理菜單接口豺瘤,之前應(yīng)該都創(chuàng)建好了相應(yīng)的類吆倦,只拿這一個接口做例子,另外兩個都一樣

MyUser實體類

@Data
@EqualsAndHashCode(callSuper = true)
public class MyUser extends BaseEntity<Integer>{
    private static final long serialVersionUID = -6525908145032868837L;
    private String userName;
    private String password;
    private String nickName;
    private String phone;
    private String email;
    private Integer status;
    public interface Status {
        int LOCKED = 0;
        int VALID = 1;
    }
}

UserDao中新建兩個方法坐求,分頁會用到

@Mapper
public interface UserDao {
    //分頁返回所有用戶
    @Select("SELECT * FROM my_user t ORDER BY t.id LIMIT #{startPosition}, #{limit}")
    List<MyUser> getAllUserByPage(@Param("startPosition")Integer startPosition,@Param("limit")Integer limit);

    //計算所有用戶數(shù)量
    @Select("select count(*) from My_user")
    Long countAllUser();
}

UserService和UserServiceImlpl

public interface UserService {
    Result<MyUser> getAllUsersByPage(Integer startPosition, Integer limit);
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    public Result<MyUser> getAllUsersByPage(Integer startPosition, Integer limit) {

        return Result.ok().count(userDao.countAllUser().intValue()).data(userDao.getAllUserByPage(startPosition,limit)).code(ResultCode.TABLE_SUCCESS);
    }
}

UserController

@Controller
@RequestMapping("/api/user")
@Api(tags = "用戶相關(guān)接口")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping
    @ResponseBody
    @ApiOperation(value = "用戶列表")
    public Result<MyUser> index(PageTableRequest pageTableRequest){
        pageTableRequest.countOffset();
        return userService.getAllUsersByPage(pageTableRequest.getOffset(),pageTableRequest.getLimit());
    }
}

我們可以比較一下他需要的json(user.json蚕泽,在admin/data/user.json)和我們返回的json格式

![swaggerjson.png](https://upload-images.jianshu.io/upload_images/13222772-cee7af8d96464bab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在這里插入圖片描述

他原先設(shè)置空值的可以不看,說明也用不著,然后在usr.html中把對應(yīng)相同的數(shù)據(jù)须妻,但是命名不一樣的地方修改一下即可仔蝌。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="utf-8">
        <title></title>
        <link rel="stylesheet" th:href="@{/PearAdmin/component/layui/css/layui.css}" />
        <link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearCommon.css}"/>
    </head>
    <body class="pear-container">
        <div class="layui-card">
            <div class="layui-card-body">
                <form class="layui-form" action="">
                    <div class="layui-form-item">
                        <label class="layui-form-label">用戶名</label>
                        <div class="layui-input-inline">
                            <input type="text" name="nickName" placeholder="" class="layui-input">
                        </div>
                        <label class="layui-form-label">賬號</label>
                        <div class="layui-input-inline">
                            <input type="text" name="userName" placeholder="" class="layui-input">
                        </div>
                        <label class="layui-form-label">地點</label>
                        <div class="layui-input-inline">
                            <select name="city" lay-verify="required">
                                    <option value=""></option>
                                    <option value="0">北京</option>
                                    <option value="1">上海</option>
                                    <option value="2">廣州</option>
                                    <option value="3">深圳</option>
                                    <option value="4">杭州</option>
                                  </select>
                        </div>
                        <button class="pear-btn pear-btn-md pear-btn-primary" lay-submit lay-filter="user-query">
                            <i class="layui-icon layui-icon-search"></i>
                            查詢
                        </button>
                        <button type="reset" class="pear-btn pear-btn-md">
                            <i class="layui-icon layui-icon-refresh"></i>
                            重置
                        </button>
                    </div>
                </form>
            </div>
        </div>
        <div class="layui-card">
            <div class="layui-card-body">
                <table id="user-table" lay-filter="user-table"></table>
            </div>
        </div>

        <script type="text/html" id="user-toolbar">
            <button class="pear-btn pear-btn-primary pear-btn-md" lay-event="add">
                <i class="layui-icon layui-icon-add-1"></i>
                新增
            </button>
            <button class="pear-btn pear-btn-danger pear-btn-md" lay-event="batchRemove">
                <i class="layui-icon layui-icon-delete"></i>
                刪除
            </button>
        </script>
        
        <script type="text/html" id="user-bar">
            <button class="pear-btn pear-btn-primary pear-btn-sm" lay-event="edit"><i class="layui-icon layui-icon-edit"></i></button>
            <button class="pear-btn pear-btn-danger pear-btn-sm" lay-event="remove"><i class="layui-icon layui-icon-delete"></i></button>
        </script>
        
        <script type="text/html" id="user-status">
            <input type="checkbox" name="status" value="{{d.id}}" lay-skin="switch" lay-text="啟用|禁用" lay-filter="user-status" checked = "{{ d.status == 0 ? 'true' : 'false' }}">
        </script>

        
        <script type="text/html" id="user-createTime">
            {{layui.util.toDateString(d.createTime, 'yyyy-MM-dd HH:mm:ss')}}
        </script>

        <script th:src="@{/PearAdmin/component/layui/layui.js}" charset="utf-8"></script>
        <script>
            layui.use(['table','form','jquery'],function () {
                let table = layui.table;
                let form = layui.form;
                let $ = layui.jquery;
                let MODULE_PATH = "operate/";
                //這里對應(yīng)的field要和自己返回的json名稱一致
                let cols = [
                    [
                        {type:'checkbox'},
                        {title: '賬號', field: 'userName', align:'center', width:100},
                        {title: '姓名', field: 'nickName', align:'center'},
                        {title: '電話', field: 'phone', align:'center'},
                        {title: '郵箱', field: 'email', align:'center'},
                        {title: '啟用', field: 'status', align:'center', templet:'#user-status'},
                        {title: '創(chuàng)建時間', field: 'createTime', align:'center',templet:'#user-createTime'},
                        {title: '操作', toolbar: '#user-bar', align:'center', width:130}
                    ]
                ]
        
                table.render({
                    elem: '#user-table',
                    url: '/api/user',//+++++++++++看這里  這里的url換成自己接口的url++++++++++++++
                    page: true ,
                    cols: cols ,
                    skin: 'line',
                    toolbar: '#user-toolbar',
                    defaultToolbar: [{
                        layEvent: 'refresh',
                        icon: 'layui-icon-refresh',
                    }, 'filter', 'print', 'exports']
                });
        
                table.on('tool(user-table)', function(obj){
                    if(obj.event === 'remove'){
                        window.remove(obj);
                    } else if(obj.event === 'edit'){
                        window .edit(obj);
                    }
                });
        
                table.on('toolbar(user-table)', function(obj){
                    if(obj.event === 'add'){
                        window.add();
                    } else if(obj.event === 'refresh'){
                        window.refresh();
                    } else if(obj.event === 'batchRemove'){
                        window.batchRemove(obj);
                    }
                });
        
                form.on('submit(user-query)', function(data){
                    table.reload('user-table',{where:data.field})
                    return false;
                });
        
                form.on('switch(user-status)', function(obj){
                    layer.tips(this.value + ' ' + this.name + ':'+ obj.elem.checked, obj.othis);
                });
        
                window.add = function(){
                    layer.open({
                        type: 2,
                        title: '新增',
                        shade: 0.1,
                        area: ['500px', '400px'],
                        content: MODULE_PATH + 'add.html'
                    });
                }
                window.edit = function(obj){
                    layer.open({
                        type: 2,
                        title: '修改',
                        shade: 0.1,
                        area: ['500px', '400px'],
                        content: MODULE_PATH + 'edit.html'
                    });
                }
        
                window.remove = function(obj){
                    layer.confirm('確定要刪除該用戶', {icon: 3, title:'提示'}, function(index){
                        layer.close(index);
                        let loading = layer.load();
                        $.ajax({
                            url: MODULE_PATH+"remove/"+obj.data['id'],
                            dataType:'json',
                            type:'delete',
                            success:function(result){
                                layer.close(loading);
                                if(result.success){
                                    layer.msg(result.msg,{icon:1,time:1000},function(){
                                        obj.del();
                                    });
                                }else{
                                    layer.msg(result.msg,{icon:2,time:1000});
                                }
                            }
                        })
                    });
                }
        
                window.batchRemove = function(obj){
                    let data = table.checkStatus(obj.config.id).data;
                    if(data.length === 0){
                        layer.msg("未選中數(shù)據(jù)",{icon:3,time:1000});
                        return false;
                    }
                    let ids = "";
                    for(let i = 0;i<data.length;i++){
                        ids += data[i].id+",";
                    }
                    ids = ids.substr(0,ids.length-1);
                    layer.confirm('確定要刪除這些用戶', {icon: 3, title:'提示'}, function(index){
                        layer.close(index);
                        let loading = layer.load();
                        $.ajax({
                            url: MODULE_PATH+"batchRemove/"+ids,
                            dataType:'json',
                            type:'delete',
                            success:function(result){
                                layer.close(loading);
                                if(result.success){
                                    layer.msg(result.msg,{icon:1,time:1000},function(){
                                        table.reload('user-table');
                                    });
                                }else{
                                    layer.msg(result.msg,{icon:2,time:1000});
                                }
                            }
                        })
                    });
                }
        
                window.refresh = function(param){
                    table.reload('user-table');
                }
            })
        </script>
    </body>
</html>

這樣當我們再次點擊用戶管理時,訪問的就是自己的接口了

[圖片上傳中...(admin.png-c008dd-1596544629482-0)]

原本自己看別人的教學(xué)博客時荒吏,是真的希望人家把所有的代碼一字不差的貼上來敛惊。等到自己寫的時候就覺得還是有道理的,代碼太占篇幅了绰更,還影響博客的觀感瞧挤。所以另外兩個界面我就補貼代碼了,大家仿照這個來就行儡湾。

get.jpg

放兩張圖片皿伺,讓大家看一下改完的效果。

在這里插入圖片描述

在這里插入圖片描述

數(shù)據(jù)庫文件和同步代碼在giteegithub中可以獲取

五盒粮、Druid連接池

Druid是阿里開源的數(shù)據(jù)庫連接池,作為后起之秀奠滑,性能比dbcp丹皱、c3p0更高,使用也越來越廣泛宋税。

當然Druid不僅僅是一個連接池摊崭,還有很多其他的功能。

druid的優(yōu)點

  • 高性能杰赛。性能比dbcp呢簸、c3p0高很多。
  • 只要是jdbc支持的數(shù)據(jù)庫乏屯,druid都支持根时,對數(shù)據(jù)庫的支持性好。并且Druid針對oracle辰晕、mysql做了特別優(yōu)化蛤迎。
  • 提供監(jiān)控功能『眩可以監(jiān)控sql語句的執(zhí)行時間替裆、ResultSet持有時間、返回行數(shù)窘问、更新行數(shù)辆童、錯誤次數(shù)、錯誤堆棧等信息惠赫,來了解連接池把鉴、sql語句的工作情況,方便統(tǒng)計儿咱、分析SQL的執(zhí)行性能

如何使用??

導(dǎo)入依賴纸镊,之前給的依賴中就有不用重復(fù)導(dǎo)入

        <!--druid連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

application.yml中配置

spring:
  profiles:
    active: dev
  application:
    name: my-springsecurity-plus
  datasource:
    driver:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/my-springsecurity-plus?serverTimezone=Asia/Shanghai
    username: root
    password: 180430121
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 初始化配置
      initial-size: 3
      # 最小連接數(shù)
      min-idle: 3
      # 最大連接數(shù)
      max-active: 15
      # 獲取連接超時時間
      max-wait: 5000
      # 連接有效性檢測時間
      time-between-eviction-runs-millis: 90000
      # 最大空閑時間
      min-evictable-idle-time-millis: 1800000
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false

      validation-query: select 1
      # 配置監(jiān)控統(tǒng)計攔截的filters
      filters: stat
      web-stat-filter:
        url-pattern: /*
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
      #StatViewServlet配置倍阐,說明請參考Druid Wiki,配置_StatViewServlet配置
      stat-view-servlet:
        enabled: true #是否啟用StatViewServlet默認值true
        url-pattern: /druid/*
        reset-enable: true
        login-username: admin #用戶名
        login-password: admin #密碼

更詳細的配置這里就不介紹了逗威。
然后重啟項目訪問http://localhost:8080/druid/login.html輸入用戶名密碼就可以看到界面了峰搪。

在這里插入圖片描述

呼,終于又寫完一篇凯旭,寫代碼的時候真沒感覺這么累概耻,像我這種文筆差的經(jīng)常寫著寫著就把自己寫亂了。罐呼。鞠柄。。嫉柴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厌杜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子计螺,更是在濱河造成了極大的恐慌夯尽,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件登馒,死亡現(xiàn)場離奇詭異匙握,居然都是意外死亡,警方通過查閱死者的電腦和手機陈轿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門圈纺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人麦射,你說我怎么就攤上這事蛾娶。” “怎么了潜秋?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵茫叭,是天一觀的道長。 經(jīng)常有香客問我半等,道長揍愁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任杀饵,我火速辦了婚禮莽囤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘切距。我一直安慰自己朽缎,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著话肖,像睡著了一般北秽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上最筒,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天贺氓,我揣著相機與錄音,去河邊找鬼床蜘。 笑死辙培,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的邢锯。 我是一名探鬼主播扬蕊,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丹擎!你這毒婦竟也來了尾抑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蒂培,失蹤者是張志新(化名)和其女友劉穎再愈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毁渗,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年单刁,在試婚紗的時候發(fā)現(xiàn)自己被綠了灸异。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡羔飞,死狀恐怖肺樟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逻淌,我是刑警寧澤么伯,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站卡儒,受9級特大地震影響田柔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骨望,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一硬爆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧擎鸠,春花似錦缀磕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糟把。三九已至,卻和暖如春牲剃,著一層夾襖步出監(jiān)牢的瞬間遣疯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工颠黎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留另锋,地道東北人。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓狭归,卻偏偏與公主長得像夭坪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子过椎,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359