最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Security權(quán)限管理實(shí)現(xiàn)接口動(dòng)態(tài)權(quán)限控制

 更新時(shí)間:2022年06月20日 10:22:34   作者:MacroZheng  
這篇文章主要為大家介紹了Spring?Security權(quán)限管理實(shí)現(xiàn)接口動(dòng)態(tài)權(quán)限控制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

SpringBoot實(shí)戰(zhàn)電商項(xiàng)目mall(30k+star)地址:https://github.com/macrozheng/mall

摘要

權(quán)限控管理作為后臺(tái)管理系統(tǒng)中必要的功能,mall項(xiàng)目中結(jié)合Spring Security實(shí)現(xiàn)了基于路徑的動(dòng)態(tài)權(quán)限控制,可以對(duì)后臺(tái)接口訪問進(jìn)行細(xì)粒度的控制,今天我們來講下它的后端實(shí)現(xiàn)原理。

前置知識(shí)

學(xué)習(xí)本文需要一些Spring Security的知識(shí),對(duì)Spring Security不太了解的朋友可以看下以下文章。

數(shù)據(jù)庫(kù)設(shè)計(jì)

權(quán)限管理相關(guān)表已經(jīng)重新設(shè)計(jì),將原來的權(quán)限拆分成了菜單和資源,菜單管理用于控制前端菜單的顯示和隱藏,資源管理用來控制后端接口的訪問權(quán)限。

數(shù)據(jù)庫(kù)表結(jié)構(gòu)

其中ums_admin、ums_roleums_admin_role_relation為原來的表,其他均為新增表。

數(shù)據(jù)庫(kù)表介紹

接下來我們將對(duì)每張表的用途做個(gè)詳細(xì)介紹。

ums_admin

后臺(tái)用戶表,定義了后臺(tái)用戶的一些基本信息。

create table ums_admin
(
   id                   bigint not null auto_increment,
   username             varchar(64) comment '用戶名',
   password             varchar(64) comment '密碼',
   icon                 varchar(500) comment '頭像',
   email                varchar(100) comment '郵箱',
   nick_name            varchar(200) comment '昵稱',
   note                 varchar(500) comment '備注信息',
   create_time          datetime comment '創(chuàng)建時(shí)間',
   login_time           datetime comment '最后登錄時(shí)間',
   status               int(1) default 1 comment '帳號(hào)啟用狀態(tài):0->禁用;1->啟用',
   primary key (id)
);

ums_role

后臺(tái)用戶角色表,定義了后臺(tái)用戶角色的一些基本信息,通過給后臺(tái)用戶分配角色來實(shí)現(xiàn)菜單和資源的分配。

create table ums_role
(
   id                   bigint not null auto_increment,
   name                 varchar(100) comment '名稱',
   description          varchar(500) comment '描述',
   admin_count          int comment '后臺(tái)用戶數(shù)量',
   create_time          datetime comment '創(chuàng)建時(shí)間',
   status               int(1) default 1 comment '啟用狀態(tài):0->禁用;1->啟用',
   sort                 int default 0,
   primary key (id)
);

ums_admin_role_relation

后臺(tái)用戶和角色關(guān)系表,多對(duì)多關(guān)系表,一個(gè)角色可以分配給多個(gè)用戶。

create table ums_admin_role_relation
(
   id                   bigint not null auto_increment,
   admin_id             bigint,
   role_id              bigint,
   primary key (id)
);

ums_menu

后臺(tái)菜單表,用于控制后臺(tái)用戶可以訪問的菜單,支持隱藏、排序和更改名稱、圖標(biāo)。

create table ums_menu
(
   id                   bigint not null auto_increment,
   parent_id            bigint comment '父級(jí)ID',
   create_time          datetime comment '創(chuàng)建時(shí)間',
   title                varchar(100) comment '菜單名稱',
   level                int(4) comment '菜單級(jí)數(shù)',
   sort                 int(4) comment '菜單排序',
   name                 varchar(100) comment '前端名稱',
   icon                 varchar(200) comment '前端圖標(biāo)',
   hidden               int(1) comment '前端隱藏',
   primary key (id)
);

ums_resource

后臺(tái)資源表,用于控制后臺(tái)用戶可以訪問的接口,使用了Ant路徑的匹配規(guī)則,可以使用通配符定義一系列接口的權(quán)限。

create table ums_resource
(
   id                   bigint not null auto_increment,
   category_id          bigint comment '資源分類ID',
   create_time          datetime comment '創(chuàng)建時(shí)間',
   name                 varchar(200) comment '資源名稱',
   url                  varchar(200) comment '資源URL',
   description          varchar(500) comment '描述',
   primary key (id)
);

ums_resource_category

后臺(tái)資源分類表,在細(xì)粒度進(jìn)行權(quán)限控制時(shí),可能資源會(huì)比較多,所以設(shè)計(jì)了個(gè)資源分類的概念,便于給角色分配資源。

create table ums_resource_category
(
   id                   bigint not null auto_increment,
   create_time          datetime comment '創(chuàng)建時(shí)間',
   name                 varchar(200) comment '分類名稱',
   sort                 int(4) comment '排序',
   primary key (id)
);

ums_role_menu_relation

后臺(tái)角色菜單關(guān)系表,多對(duì)多關(guān)系,可以給一個(gè)角色分配多個(gè)菜單。

create table ums_role_menu_relation
(
   id                   bigint not null auto_increment,
   role_id              bigint comment '角色I(xiàn)D',
   menu_id              bigint comment '菜單ID',
   primary key (id)
);

ums_role_resource_relation

后臺(tái)角色資源關(guān)系表,多對(duì)多關(guān)系,可以給一個(gè)角色分配多個(gè)資源。

create table ums_role_resource_relation
(
   id                   bigint not null auto_increment,
   role_id              bigint comment '角色I(xiàn)D',
   resource_id          bigint comment '資源ID',
   primary key (id)
);

結(jié)合Spring Security實(shí)現(xiàn)

實(shí)現(xiàn)動(dòng)態(tài)權(quán)限是在原mall-security模塊的基礎(chǔ)上進(jìn)行改造完成的,原實(shí)現(xiàn)有不清楚的可以自行參照前置知識(shí)中的文檔來學(xué)習(xí)。

以前的權(quán)限控制

以前的權(quán)限控制是采用Spring Security的默認(rèn)機(jī)制實(shí)現(xiàn)的,下面我們以商品模塊的代碼為例來講講實(shí)現(xiàn)原理。

首先我們?cè)谛枰獧?quán)限的接口上使用@PreAuthorize注解定義好需要的權(quán)限;

/**
 * 商品管理Controller
 * Created by macro on 2018/4/26.
 */
@Controller
@Api(tags = "PmsProductController", description = "商品管理")
@RequestMapping("/product")
public class PmsProductController {
    @Autowired
    private PmsProductService productService;
    @ApiOperation("創(chuàng)建商品")
    @RequestMapping(value = "/create", method = RequestMethod.POST)
    @ResponseBody
    @PreAuthorize("hasAuthority('pms:product:create')")
    public CommonResult create(@RequestBody PmsProductParam productParam, BindingResult bindingResult) {
        int count = productService.create(productParam);
        if (count > 0) {
            return CommonResult.success(count);
        } else {
            return CommonResult.failed();
        }
    }
}

然后將該權(quán)限值存入到權(quán)限表中,當(dāng)用戶登錄時(shí),將其所擁有的權(quán)限查詢出來;

/**
 * UmsAdminService實(shí)現(xiàn)類
 * Created by macro on 2018/4/26.
 */
@Service
public class UmsAdminServiceImpl implements UmsAdminService {
    @Override
    public UserDetails loadUserByUsername(String username){
        //獲取用戶信息
        UmsAdmin admin = getAdminByUsername(username);
        if (admin != null) {
            List<UmsPermission> permissionList = getPermissionList(admin.getId());
            return new AdminUserDetails(admin,permissionList);
        }
        throw new UsernameNotFoundException("用戶名或密碼錯(cuò)誤");
    }
}

之后Spring Security把用戶擁有的權(quán)限值和接口上注解定義的權(quán)限值進(jìn)行比對(duì),如果包含則可以訪問,反之就不可以訪問;

但是這樣做會(huì)帶來一些問題,我們需要在每個(gè)接口上都定義好訪問該接口的權(quán)限值,而且只能挨個(gè)控制接口的權(quán)限,無法批量控制。其實(shí)每個(gè)接口都可以由它的訪問路徑唯一確定,我們可以使用基于路徑的動(dòng)態(tài)權(quán)限控制來解決這些問題。

基于路徑的動(dòng)態(tài)權(quán)限控制

接下來我們?cè)敿?xì)介紹下如何使用Spring Security實(shí)現(xiàn)基于路徑的動(dòng)態(tài)權(quán)限。

首先我們需要?jiǎng)?chuàng)建一個(gè)過濾器,用于實(shí)現(xiàn)動(dòng)態(tài)權(quán)限控制,這里需要注意的是doFilter方法,對(duì)于OPTIONS請(qǐng)求直接放行,否則前端調(diào)用會(huì)出現(xiàn)跨域問題。對(duì)于配置在IgnoreUrlsConfig中的白名單路徑我也需要直接放行,所有的鑒權(quán)操作都會(huì)在super.beforeInvocation(fi)中進(jìn)行。

/**
 * 動(dòng)態(tài)權(quán)限過濾器,用于實(shí)現(xiàn)基于路徑的動(dòng)態(tài)權(quán)限過濾
 * Created by macro on 2020/2/7.
 */
public class DynamicSecurityFilter extends AbstractSecurityInterceptor implements Filter {
    @Autowired
    private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;
    @Autowired
    private IgnoreUrlsConfig ignoreUrlsConfig;
    @Autowired
    public void setMyAccessDecisionManager(DynamicAccessDecisionManager dynamicAccessDecisionManager) {
        super.setAccessDecisionManager(dynamicAccessDecisionManager);
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
        //OPTIONS請(qǐng)求直接放行
        if(request.getMethod().equals(HttpMethod.OPTIONS.toString())){
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            return;
        }
        //白名單請(qǐng)求直接放行
        PathMatcher pathMatcher = new AntPathMatcher();
        for (String path : ignoreUrlsConfig.getUrls()) {
            if(pathMatcher.match(path,request.getRequestURI())){
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
                return;
            }
        }
        //此處會(huì)調(diào)用AccessDecisionManager中的decide方法進(jìn)行鑒權(quán)操作
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }
    @Override
    public void destroy() {
    }
    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }
    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return dynamicSecurityMetadataSource;
    }
}

在DynamicSecurityFilter中調(diào)用super.beforeInvocation(fi)方法時(shí)會(huì)調(diào)用AccessDecisionManager中的decide方法用于鑒權(quán)操作,而decide方法中的configAttributes參數(shù)會(huì)通過SecurityMetadataSource中的getAttributes方法來獲取,configAttributes其實(shí)就是配置好的訪問當(dāng)前接口所需要的權(quán)限,下面是簡(jiǎn)化版的beforeInvocation源碼。

public abstract class AbstractSecurityInterceptor implements InitializingBean,
		ApplicationEventPublisherAware, MessageSourceAware {
protected InterceptorStatusToken beforeInvocation(Object object) {
        //獲取元數(shù)據(jù)
		Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
				.getAttributes(object);
		Authentication authenticated = authenticateIfRequired();
		//進(jìn)行鑒權(quán)操作
		try {
			this.accessDecisionManager.decide(authenticated, object, attributes);
		}
		catch (AccessDeniedException accessDeniedException) {
			publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
					accessDeniedException));
			throw accessDeniedException;
		}
	}
}

知道了鑒權(quán)的原理,接下來我們需要自己實(shí)現(xiàn)SecurityMetadataSource接口的getAttributes方法,用于獲取當(dāng)前訪問路徑所需資源。

/**
 * 動(dòng)態(tài)權(quán)限數(shù)據(jù)源,用于獲取動(dòng)態(tài)權(quán)限規(guī)則
 * Created by macro on 2020/2/7.
 */
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    private static Map<String, ConfigAttribute> configAttributeMap = null;
    @Autowired
    private DynamicSecurityService dynamicSecurityService;
    @PostConstruct
    public void loadDataSource() {
        configAttributeMap = dynamicSecurityService.loadDataSource();
    }
    public void clearDataSource() {
        configAttributeMap.clear();
        configAttributeMap = null;
    }
    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        if (configAttributeMap == null) this.loadDataSource();
        List<ConfigAttribute>  configAttributes = new ArrayList<>();
        //獲取當(dāng)前訪問的路徑
        String url = ((FilterInvocation) o).getRequestUrl();
        String path = URLUtil.getPath(url);
        PathMatcher pathMatcher = new AntPathMatcher();
        Iterator<String> iterator = configAttributeMap.keySet().iterator();
        //獲取訪問該路徑所需資源
        while (iterator.hasNext()) {
            String pattern = iterator.next();
            if (pathMatcher.match(pattern, path)) {
                configAttributes.add(configAttributeMap.get(pattern));
            }
        }
        // 未設(shè)置操作請(qǐng)求權(quán)限,返回空集合
        return configAttributes;
    }
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }
    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

由于我們的后臺(tái)資源規(guī)則被緩存在了一個(gè)Map對(duì)象之中,所以當(dāng)后臺(tái)資源發(fā)生變化時(shí),我們需要清空緩存的數(shù)據(jù),然后下次查詢時(shí)就會(huì)被重新加載進(jìn)來。

這里我們需要修改UmsResourceController類,注入DynamicSecurityMetadataSource,當(dāng)修改后臺(tái)資源時(shí),需要調(diào)用clearDataSource方法來清空緩存的數(shù)據(jù)。

/**
 * 后臺(tái)資源管理Controller
 * Created by macro on 2020/2/4.
 */
@Controller
@Api(tags = "UmsResourceController", description = "后臺(tái)資源管理")
@RequestMapping("/resource")
public class UmsResourceController {
    @Autowired
    private UmsResourceService resourceService;
    @Autowired
    private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;
    @ApiOperation("添加后臺(tái)資源")
    @RequestMapping(value = "/create", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult create(@RequestBody UmsResource umsResource) {
        int count = resourceService.create(umsResource);
        dynamicSecurityMetadataSource.clearDataSource();
        if (count &gt; 0) {
            return CommonResult.success(count);
        } else {
            return CommonResult.failed();
        }
    }
 }

之后我們需要實(shí)現(xiàn)AccessDecisionManager接口來實(shí)現(xiàn)權(quán)限校驗(yàn),對(duì)于沒有配置資源的接口我們直接允許訪問,對(duì)于配置了資源的接口,我們把訪問所需資源和用戶擁有的資源進(jìn)行比對(duì),如果匹配則允許訪問。

/**
 * 動(dòng)態(tài)權(quán)限決策管理器,用于判斷用戶是否有訪問權(quán)限
 * Created by macro on 2020/2/7.
 */
public class DynamicAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object object,
                       Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        // 當(dāng)接口未被配置資源時(shí)直接放行
        if (CollUtil.isEmpty(configAttributes)) {
            return;
        }
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        while (iterator.hasNext()) {
            ConfigAttribute configAttribute = iterator.next();
            //將訪問所需資源或用戶擁有資源進(jìn)行比對(duì)
            String needAuthority = configAttribute.getAttribute();
            for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
                if (needAuthority.trim().equals(grantedAuthority.getAuthority())) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("抱歉,您沒有訪問權(quán)限");
    }
    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }
    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

我們之前在DynamicSecurityMetadataSource中注入了一個(gè)DynamicSecurityService對(duì)象,它是我自定義的一個(gè)動(dòng)態(tài)權(quán)限業(yè)務(wù)接口,其主要用于加載所有的后臺(tái)資源規(guī)則。

/**
 * 動(dòng)態(tài)權(quán)限相關(guān)業(yè)務(wù)類
 * Created by macro on 2020/2/7.
 */
public interface DynamicSecurityService {
    /**
     * 加載資源ANT通配符和資源對(duì)應(yīng)MAP
     */
    Map<String, ConfigAttribute> loadDataSource();
}

接下來我們需要修改Spring Security的配置類SecurityConfig,當(dāng)有動(dòng)態(tài)權(quán)限業(yè)務(wù)類時(shí)在FilterSecurityInterceptor過濾器前添加我們的動(dòng)態(tài)權(quán)限過濾器。

這里在創(chuàng)建動(dòng)態(tài)權(quán)限相關(guān)對(duì)象時(shí),還使用了@ConditionalOnBean這個(gè)注解,當(dāng)沒有動(dòng)態(tài)權(quán)限業(yè)務(wù)類時(shí)就不會(huì)創(chuàng)建動(dòng)態(tài)權(quán)限相關(guān)對(duì)象,實(shí)現(xiàn)了有動(dòng)態(tài)權(quán)限控制和沒有這兩種情況的兼容。

/**
 * 對(duì)SpringSecurity的配置的擴(kuò)展,支持自定義白名單資源路徑和查詢用戶邏輯
 * Created by macro on 2019/11/5.
 */
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired(required = false)
    private DynamicSecurityService dynamicSecurityService;
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
                .authorizeRequests();
        //有動(dòng)態(tài)權(quán)限配置時(shí)添加動(dòng)態(tài)權(quán)限校驗(yàn)過濾器
        if(dynamicSecurityService!=null){
            registry.and().addFilterBefore(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
        }
    }
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicAccessDecisionManager dynamicAccessDecisionManager() {
        return new DynamicAccessDecisionManager();
    }
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicSecurityFilter dynamicSecurityFilter() {
        return new DynamicSecurityFilter();
    }
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicSecurityMetadataSource dynamicSecurityMetadataSource() {
        return new DynamicSecurityMetadataSource();
    }
}

這里還有個(gè)問題需要提下,當(dāng)前端跨域訪問沒有權(quán)限的接口時(shí),會(huì)出現(xiàn)跨域問題,只需要在沒有權(quán)限訪問的處理類RestfulAccessDeniedHandler中添加允許跨域訪問的響應(yīng)頭即可。

/**
 * 自定義返回結(jié)果:沒有權(quán)限訪問時(shí)
 * Created by macro on 2018/4/26.
 */
public class RestfulAccessDeniedHandler implements AccessDeniedHandler{
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Cache-Control","no-cache");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(JSONUtil.parse(CommonResult.forbidden(e.getMessage())));
        response.getWriter().flush();
    }
}

當(dāng)我們其他模塊需要?jiǎng)討B(tài)權(quán)限控制時(shí),只要?jiǎng)?chuàng)建一個(gè)DynamicSecurityService對(duì)象就行了,比如在mall-admin模塊中我們啟用了動(dòng)態(tài)權(quán)限功能。

/**
 * mall-security模塊相關(guān)配置
 * Created by macro on 2019/11/9.
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MallSecurityConfig extends SecurityConfig {
    @Autowired
    private UmsAdminService adminService;
    @Autowired
    private UmsResourceService resourceService;
    @Bean
    public UserDetailsService userDetailsService() {
        //獲取登錄用戶信息
        return username -&gt; adminService.loadUserByUsername(username);
    }
    @Bean
    public DynamicSecurityService dynamicSecurityService() {
        return new DynamicSecurityService() {
            @Override
            public Map&lt;String, ConfigAttribute&gt; loadDataSource() {
                Map&lt;String, ConfigAttribute&gt; map = new ConcurrentHashMap&lt;&gt;();
                List&lt;UmsResource&gt; resourceList = resourceService.listAll();
                for (UmsResource resource : resourceList) {
                    map.put(resource.getUrl(), new org.springframework.security.access.SecurityConfig(resource.getId() + ":" + resource.getName()));
                }
                return map;
            }
        };
    }
}

權(quán)限管理功能演示

具體參考:大家心心念念的權(quán)限管理功能,這次安排上了!

mall項(xiàng)目更新源碼地址 https://github.com/macrozheng/mall

以上就是Spring Security權(quán)限管理實(shí)現(xiàn)接口動(dòng)態(tài)權(quán)限控制的詳細(xì)內(nèi)容,更多關(guān)于Spring Security接口動(dòng)態(tài)權(quán)限控制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JAVA?流程控制專項(xiàng)精講

    JAVA?流程控制專項(xiàng)精講

    不喜歡羅里吧嗦,講的很精簡(jiǎn)易懂。從基礎(chǔ)開始講,后續(xù)會(huì)講到JAVA高級(jí),中間會(huì)穿插面試題和項(xiàng)目實(shí)戰(zhàn),希望能給大家?guī)韼椭?/div> 2022-03-03
  • 深入了解SpringMVC初始化流程

    深入了解SpringMVC初始化流程

    框架源碼是我們?Coding?晉級(jí)中的必修課,SSM?應(yīng)該算是小伙伴們?nèi)粘=佑|最多的框架了,這其中?SpringMVC?初始化流程相對(duì)來說要簡(jiǎn)單一些,因此本文就先來和大家分析一下?SpringMVC?初始化流程
    2022-07-07
  • Java中的==使用方法詳解

    Java中的==使用方法詳解

    這篇文章主要給大家介紹了關(guān)于Java中的==使用方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-09-09
  • 使用Spring的攔截器監(jiān)測(cè)每個(gè)Controller或方法的執(zhí)行時(shí)長(zhǎng)

    使用Spring的攔截器監(jiān)測(cè)每個(gè)Controller或方法的執(zhí)行時(shí)長(zhǎng)

    這篇文章主要介紹了使用Spring的攔截器監(jiān)測(cè)每個(gè)Controller或方法的執(zhí)行時(shí)長(zhǎng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java實(shí)現(xiàn)矩陣乘法以及優(yōu)化的方法實(shí)例

    Java實(shí)現(xiàn)矩陣乘法以及優(yōu)化的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)矩陣乘法以及優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 淺談在Spring中如何使用數(shù)據(jù)源(DBCP、C3P0、JNDI)

    淺談在Spring中如何使用數(shù)據(jù)源(DBCP、C3P0、JNDI)

    這篇文章主要介紹了淺談在Spring中如何使用數(shù)據(jù)源(DBCP、C3P0、JNDI),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-10-10
  • Spring定時(shí)任務(wù)實(shí)現(xiàn)與配置(一)

    Spring定時(shí)任務(wù)實(shí)現(xiàn)與配置(一)

    這篇文章主要為大家詳細(xì)介紹了Spring定時(shí)任務(wù)的實(shí)現(xiàn)與配置第一篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Spring Boot數(shù)據(jù)庫(kù)鏈接池配置方法

    Spring Boot數(shù)據(jù)庫(kù)鏈接池配置方法

    這篇文章主要介紹了Spring Boot數(shù)據(jù)庫(kù)鏈接池配置方法,需要的朋友可以參考下
    2017-04-04
  • SpringBoot動(dòng)態(tài)Feign服務(wù)調(diào)用詳解

    SpringBoot動(dòng)態(tài)Feign服務(wù)調(diào)用詳解

    Feign是Netflix公司開發(fā)的一個(gè)聲明式的REST調(diào)用客戶端; Ribbon負(fù)載均衡、 Hystrⅸ服務(wù)熔斷是我們Spring Cloud中進(jìn)行微服務(wù)開發(fā)非?;A(chǔ)的組件,在使用的過程中我們也發(fā)現(xiàn)它們一般都是同時(shí)出現(xiàn)的,而且配置也都非常相似
    2022-12-12
  • Java Web制作登錄驗(yàn)證碼實(shí)現(xiàn)代碼解析

    Java Web制作登錄驗(yàn)證碼實(shí)現(xiàn)代碼解析

    這篇文章主要介紹了Java Web制作登錄驗(yàn)證碼實(shí)現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09

最新評(píng)論

长泰县| 瓦房店市| 桑日县| 北宁市| 玉龙| 绥宁县| 新疆| 比如县| 洪洞县| 淄博市| 会理县| 鄂伦春自治旗| 陵川县| 东阿县| 云安县| 大方县| 金溪县| 监利县| 遵义县| 思茅市| 昌吉市| 卢龙县| 崇礼县| 库伦旗| 鄂尔多斯市| 贡觉县| 天全县| 龙山县| 岑溪市| 新野县| 淮南市| 永和县| 东乌| 洮南市| 二手房| 略阳县| 安龙县| 荣成市| 长海县| 三都| 永康市|