寫一個簡易的java項目(四) 登陸和權限


用到的技術:

  后台: java (springboot+shiro) 。創建項目-可參考 寫一個簡易的java項目(一)

  前台: vue-admin-template (前台權限參考vue-element-admin)。下載配置-可參考 寫一個簡易的java項目(三)

編輯器:

  后台:IntelliJ IDEA 

  前台:Visual Studio Code

后台:

第一步:打印日志 &確認前台傳過來的參數:賬號密碼

 這里我使用fastjson的方法 獲取用戶密碼,代碼如下

pom:

    <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
View Code

 登陸打印結果:

第二步: 這里我們先創建三張表:

因為只是登陸 還沒到權限所以 主要是用戶表: 存一些基本信息如 賬號 密碼 頭像 密碼鹽(如果需要的話) 角色id

  sys_user 用戶

  sys_role 角色

  sys_permission 權限

用戶表:

CREATE TABLE `sys_user` (
  `user_id` bigint NOT NULL COMMENT '主鍵id',
  `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '頭像',
  `account` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '賬號',
  `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密碼',
  `salt` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密碼鹽',
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '名字',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `sex` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '性別',
  `email` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '郵箱',
  `phone` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '電話',
  `role_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '角色id(多個逗號隔開)',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `create_user` bigint DEFAULT NULL COMMENT '創建人',
  `update_time` datetime DEFAULT NULL COMMENT '更新時間',
  `update_user` bigint DEFAULT NULL COMMENT '更新人',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用戶表';
View Code

角色表:

CREATE TABLE `sys_role` (
  `role_id` bigint NOT NULL COMMENT '主鍵id',
  `pid` bigint DEFAULT NULL COMMENT '父角色id',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '角色名稱',
  `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述',
  `sort` int DEFAULT NULL COMMENT '序號',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `update_time` datetime DEFAULT NULL COMMENT '修改時間',
  `create_user` bigint DEFAULT NULL COMMENT '創建用戶',
  `update_user` bigint DEFAULT NULL COMMENT '修改用戶',
  `deleted` tinyint(1) DEFAULT '0' COMMENT '邏輯刪除',
  PRIMARY KEY (`role_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='角色表';
View Code

權限表:

CREATE TABLE `sys_permission` (
  `id` int NOT NULL AUTO_INCREMENT,
  `role_id` int DEFAULT NULL COMMENT '角色ID',
  `permission` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '權限',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `update_time` datetime DEFAULT NULL COMMENT '更新時間',
  `deleted` tinyint(1) DEFAULT '0' COMMENT '邏輯刪除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='權限表';
View Code

 

第三步:shiro 權限認證

  1.pom:

    <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.4.0</version>
        </dependency>

   2.自定義Realm 主要作用有:驗證登陸人的賬號密碼是否正確、驗證賬號的權限信息等等

   extends AuthorizingRealm 重寫兩個方法:

      doGetAuthorizationInfo(PrincipalCollection principalCollection) 

      doGetAuthenticationInfo(AuthenticationToken authenticationToken) 

   

KingRealm

 第一個方法:授權:這里需要寫一些方法->通過角色id 獲取角色名稱 和 權限信息

  /**
     * 權限認證
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 獲取用戶
        User user = (User) principalCollection.getPrimaryPrincipal();
        String roleIds = user.getRoleIds();

        // 通過角色id獲取用戶權限
        Set<String> roles = roleService.getRolesByRoleIds(roleIds);
        Set<String> permissions = permissionService.getPermissionsByRoleIds(roleIds);

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roles);
        info.setStringPermissions(permissions);
        return info;
    }

   service

public Set<String> getPermissionsByRoleIds(String roleIds) {
        Set<String> permissions = new HashSet<String>();
        if (StringUtils.isEmpty(roleIds)) {
            return permissions;
        }

        List<Permission> permissionList = permissionMapper.getPermissionsByRoleIds(roleIds);

        for (Permission permission : permissionList) {
            permissions.add(permission.getPermission());
        }

        return permissions;
}

第二個方法:認證:這里需要一個方法-》就是通過賬號獲取用戶信息 

  /**
     * 登錄認證
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String password = new String(token.getPassword());

        if (StringUtils.isEmpty(username)) {
            throw new AccountException("用戶名不能為空");
        }
        if (StringUtils.isEmpty(password)) {
            throw new AccountException("密碼不能為空");
        }

        // 根據用戶名從數據庫中查詢該用戶
        User user = userService.getByUsername(username);
        if(user == null) {
            throw new UnknownAccountException("賬號或密碼不正確");// 不存在該賬號
        }
        // 驗證賬號密碼是否正確 這里使用 :Md5(token密碼+鹽) = 數據庫密碼 的方式
        String requestPassword = SaltMd5Util.toMd5String(password, user.getSalt());// token 中的password
        String dbPassword = user.getPassword();// 數據庫中的 password
        if (dbPassword == null || !dbPassword.equalsIgnoreCase(requestPassword)) {
            throw new UnknownAccountException("賬號或密碼不正確");
        }
        // 把當前用戶存到 Session 中
        SecurityUtils.getSubject().getSession().setAttribute("user", user);
        // 傳入用戶名和密碼進行身份認證,並返回認證信息
        AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, password, getName());
        return authcInfo;

    }

  加密util:

public static String toMd5String(String password, String salt) {
        String secret = password+salt;
        return DigestUtils.md5DigestAsHex(secret.getBytes());
}

  3.shiro 配置 ShiroConfig

    首先把我們剛剛寫好的Realm 引進來:

@Configuration
public class ShiroConfig {

    @Bean
    public KingRealm KingRealm() {return new KingRealm(); }
}

    加上shiro 過濾器:

  /**
     * shiro過濾器
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 攔截器
        // anon 不會攔截
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        filterChainDefinitionMap.put("/user/logout", "anon");
        filterChainDefinitionMap.put("/user/login", "anon");
        // authc 攔截
        filterChainDefinitionMap.put("/**", "authc");
        // 默認登錄頁面地址
        shiroFilterFactoryBean.setLoginUrl("/user/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    加上安全管理器:

  /**
     * 安全管理器
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(KingRealm());return securityManager;
    }

  注解權限控制:

  切點:

  @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

  切面:

  @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

 

第四步:寫登陸、獲取用戶信息、退出登錄 三個后台接口

登陸:

   @ResponseBody
    @PostMapping("/login")
    public ResponseData login(@RequestBody String body) {
        log.info("===登陸請求===請求參數為body:{}",body);
        JSONObject json=JSONObject.parseObject(body);

        String username= (String) json.get("username");
        String password= (String) json.get("password");

        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            return ResponseData.error("賬號、密碼不能為空");
        }

        Subject currentUser = SecurityUtils.getSubject();// 獲取當前用戶信息
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.error("===登陸請求===錯誤:{}", "賬號或密碼錯誤");
                return ResponseData.error("賬號或密碼錯誤");
            } catch (Exception e) {
                log.error("===登陸請求===錯誤:{}", "賬號或密碼錯誤");
                return ResponseData.error("賬號或密碼錯誤");
            }
        }

        log.info("返回結果:{}", JSONObject.toJSONString(currentUser.getSession().getId()));
        return ResponseData.success(currentUser.getSession().getId());
    }

獲取用戶信息:

   @ResponseBody
    @RequestMapping("/info")
    public ResponseData info() {
        Subject currentUser = SecurityUtils.getSubject();
        User user = (User) currentUser.getPrincipal();

        Map<String, Object> data = new HashMap<>();
        data.put("name", user.getAccount());
        data.put("avatar", user.getAvatar());

        String roleIds = user.getRoleIds();

        // 通過角色id獲取用戶權限
        Set<String> roles = roleService.getRolesByRoleIds(roleIds);
        Set<String> permissions = permissionService.getPermissionsByRoleIds(roleIds);
        data.put("roles", roles);
        data.put("permissions", permissions);

        log.info("用戶信息:{}", JSONObject.toJSONString(data));
        return ResponseData.success(data);
  }

退出登錄:

   @ResponseBody
    @PostMapping("/logout")
    public ResponseData login() {
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.logout();

        log.info("===退出登錄===:{}", JSONObject.toJSONString(currentUser.getSession().getId()));
        return ResponseData.success();
    }

看一下測試效果:

失敗:

 

 控制台輸出:

 成功:

控制台輸出:

 點擊退出->

回到了登錄頁面

控制台輸出:

這是我之前的測試頁面,做了簡單的增刪改查:

 怎樣給admin 這個用戶添加權限?

 后台:

直接加注解看看:

 ###如果出現這種問題:

404

 

 解決一下這個問題:原因是 在ShiroConfig 中少加了代碼:

  @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

###

前台:

###插曲 -了解一下vue-admin-template 的登陸驗證  > <。

它用到了vuex, 什么是vuex?-》》vuex 學習筆記

這里我改了個東西:

  登錄的返回值。因為后台我直接返回了token ,所以這里把 .token 去掉了 。不需要盲目的改 看自己返回的結果。

 這樣我們就可以通過 getToken() 獲取到token 了。

 

 而我們在permission.js 的 router.beforeEach 方法中 (路由攔截) 調用了此方法,判斷用戶是否登陸過了。

 #main.js 中可以看到引入了權限=》 permission.js 

 

 

 ###

其實既然沒有權限就沒必要顯示出來 -》

菜單權限:

看一下permission.js 中路由攔截的方法:

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {// 如果存在token if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {// 如果store中存在用戶名
        next()
      } else {
        try {
          // get user info 獲取用戶信息
          await store.dispatch('user/getInfo')

          next()
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          // Message.error(error || 'Has Error')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {// 沒有token /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {// 白名單免登陸 // in the free login whitelist, go directly
      next()
    } else {// 重定向到首頁 // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

思路:獲取用戶信息后把權限信息也存起來,然后處理菜單只顯示有權限的菜單。

第一步:獲取后台的權限信息

  看一下前台可以不可獲取用戶的權限信息,如果可以 我們需要把權限信息存起來。 

  用戶信息存放的位置在-vuex:src/store/modules/user.js 

state中定義兩個變量roles 和permissions 分別存后台傳過來的角色名稱和權限。

mutations 寫好對應的方法,以便調用賦值。

 getters

后台傳過來的值:

  打印了一下 getInfo 返回的data,大概是這樣 :

 找到getInfo方法 給這兩個參數賦值。在退出登錄時清空。

第二步:處理菜單只顯示有權限的部分

這里為了省事,就直接把 vue-element-admin 中的代碼粘過來,改一改好了。o.o

首先是:permission.js 

  然后是store->permission

  然后是index

  getter

 改動:

  第一步:由於我想用權限信息 permissions 來確定菜單,而不是用戶的角色。所以過濾菜單的方法傳參 傳permissions。

   同理,permission.js 中所有的role 都改成了permission 也是為了代碼的可讀性。

  第二步: permission.js 中傳的參數 asyncRoutes 

 

  不需要權限的:

   需要權限的:為了測試,現在把測試菜單放到這下面:

 

 現在 router 中的代碼:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'

/**
 * Note: sub-menu only appear when route children.length >= 1
 * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
 *
 * hidden: true                   if set true, item will not show in the sidebar(default is false)
 * alwaysShow: true               if set true, will always show the root menu
 *                                if not set alwaysShow, when item has more than one children route,
 *                                it will becomes nested mode, otherwise not show the root menu
 * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb
 * name:'router-name'             the name is used by <keep-alive> (must set!!!)
 * meta : {
    roles: ['admin','editor']    control the page roles (you can set multiple roles)
    title: 'title'               the name show in sidebar and breadcrumb (recommend set)
    icon: 'svg-name'             the icon show in the sidebar
    breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
    activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
  }
 */

/**
 * constantRoutes
 * a base page that does not have permission requirements
 * all roles can be accessed
 */
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: '首頁', icon: 'dashboard' }
    }]
  }

  // 404 page must be placed at the end !!!
  // { path: '*', redirect: '/404', hidden: true }
]

export const asyncRoutes = [
  {
    path: '/example',
    component: Layout,
    redirect: 'noredirect',
    alwaysShow: true,
    name: 'Example',
    meta: {
      permissions: ['/example'],
      title: '測試',
      icon: 'example' },
    children: [
      {
        path: 'table',
        name: '表格',
        component: () => import('@/views/mytable/index'),
        meta: {
          permissions: ['/example/table'],
          title: '測試表格',
          icon: 'table'
        }
      },
      {
        path: 'other',
        name: '其他',
        component: () => import('@/views/table/index'),
        meta: {
          permissions: ['/example/other'],
          title: '測試其他',
          icon: 'table'
        }
      }
    ]
  },
  // 404 page must be placed at the end !!!
  { path: '*', redirect: '/404', hidden: true }
]

const createRouter = () => new Router({
  // mode: 'history', // require service support
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router
View Code

@/permission.js 中代碼

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // store.dispatch('user/getInfo')
          // next()
          store.dispatch('user/getInfo').then(res => {
            // generate accessible routes map based on roles
            store.dispatch('permission/generateRoutes', res.permissions).then(() => {
              // dynamically add accessible routes
              debugger
              router.addRoutes(store.getters.addRoutes)
              // hack method to ensure that addRoutes is complete
              // set the replace: true, so the navigation will not leave a history record
              next({ ...to, replace: true })
            })
          })
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          // Message.error(error || 'Has Error')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})
View Code

   第三步:渲染 -》 改成自己的 ok!

 

 數據庫:

用戶:

 權限

效果:

 按鈕權限:

同理為了方便,我們把vue-element-admin 中的utils/permission.js 粘貼過來,做個簡單修改。

第一步,粘貼

 同樣,把roles 改成permissions

第二步:粘貼 @/directive/permission/index.js  權限判斷指令

 同樣,把role 改成permission

 main.js

import permission from '@/directive/permission/index.js' // 權限判斷指令
Vue.directive('permission', permission)

 頁面:

 沒有權限時:

 有權限時:

 數據庫:

 解決問題&補充:

 問題一:把前台打包放到項目下啟動后出現如下錯誤:

 排查錯誤引發原因得出結論:是shiro 攔截引起的。

Uncaught SyntaxError: Unexpected token '<'

解決方案:放過static 下的靜態文件即可

filterChainDefinitionMap.put("/static/**", "anon");

 問題二:在本地啟動沒有問題,打包后就出現如下問題:

 可能導致這個問題的原因有很多。這里我的問題竟然是:。。。 clean 之后直接打包導致的。

2020-10-10 15:11:41.962  INFO 8784 --- [ost-startStop-1] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-10-10 15:11:41.966 ERROR 8784 --- [ost-startStop-1] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
        If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
        If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).

 正確的操作應該是 clean ->build->package 

問題三: 退出登錄之后,點擊菜單時:url 雖然改變了,但頁面空白。點擊 enter 刷新后 又可顯示頁面。。

解決方案:

代碼:

await this.$store.dispatch('user/logout').then(() => {
        location.reload()
})

問題四:獲取用戶信息失敗時,跳到登錄頁避免bug

 代碼:

store.dispatch('user/getInfo').then(res => {
          // generate accessible routes map based on roles
          store.dispatch('permission/generateRoutes', res.permissions).then(() => {
              // dynamically add accessible routes
              router.addRoutes(store.getters.addRoutes)
              // hack method to ensure that addRoutes is complete
              // set the replace: true, so the navigation will not leave a history record
              next({ ...to, replace: true })
            })
          }).catch((error) => {
            store.dispatch('user/resetToken').then(() => {
              Message.error(error || '請重新登陸')
              next({ path: '/' })
          })
})

補充一:在控制台打印mybatis SQL 語句

logging:
  level:
    com.example.king:  DEBUG

控制台輸出:

 補充二:配置 swagger 

自動生成在線開發文檔,方便測試等優點

 pom

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

配置:

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())// 限制包
                .paths(PathSelectors.any())// 限制控制器
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("King")
                .description("king-接口文檔")
                .contact("DarGi")
                .version("1.0")
                .build();
    }
}

shiroConfig 中放行:

     filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        filterChainDefinitionMap.put("/swagger/**", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**", "anon");
        filterChainDefinitionMap.put("/v2/**", "anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/configuration/**", "anon");

頁面:http://localhost:8091/swagger-ui.html#/

 

 

 做個測試:

 

 返回結果

 

 

@


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM