Filter过滤器学习使用

验证token

对外API过滤器
public class APIFilter implements Filter {private static Logger logger = LogManager.getLogger(APIFilter.class);private ICachedTokenService tokenService;public APIFilter(ICachedTokenService tokenService) {super();this.tokenService = tokenService;}@Overridepublic void init(FilterConfig arg0) throws ServletException {}@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {HttpServletRequest hreq = (HttpServletRequest) req;HttpServletResponse hres = (HttpServletResponse) resp;//设置一些Header其他信息hres.setHeader("Access-Control-Allow-Origin", hreq.getHeader("Origin"));hres.setHeader("Access-Control-Allow-Credentials", "true");hres.setHeader("Access-Control-Allow-Methods", hreq.getMethod());hres.setHeader("Access-Control-Max-Age", "86400");hres.setHeader("Access-Control-Allow-Headers", "*");//不校验权限if(hreq.getRequestURI().contains("/unauth") || hreq.getRequestURI().contains("/question")){chain.doFilter(req, resp);return;}// 如果是OPTIONS则结束请求if (HttpMethod.OPTIONS.toString().equals(hreq.getMethod())) {hres.setStatus(HttpStatus.NO_CONTENT.value());return;}try{//从请求cookie中获取access_tokenAccessTokenUser user = null;String access_token=hreq.getParameter("access_token");if(StringUtils.isBlank(access_token)){access_token= hreq.getHeader("access_token");}if(StringUtils.isBlank(access_token)){access_token=this.getCookieByCookieName("access_token", hreq);}//获取用户if(StringUtils.isNotBlank(access_token)){String token=access_token;user = ThreadLocalCache.fetchAPIData("AccessTokenUserByAccessToken:"+token+",true",() -> {ApiResultDTO<AccessTokenUser> tokenUserResp= tokenService.getAccessTokenUserByAccessToken(token, true);if(tokenUserResp.isSuccessed()) {return tokenUserResp;}else {String errorMsg = "访问令牌服务发生错误,错误码:"+tokenUserResp.getStatus()+",错误信息:"+tokenUserResp.getStatusMsg();logger.error(errorMsg);throw new RuntimeException(errorMsg);}});//判断是否存在这样的用户if(user==null) logger.error("请求地址{}根据access_token【{}】无法获取登录用户。",hreq.getRequestURI(),access_token);}if(user==null){throw new BusinessException("登录已过期,请重新登录!", ApiResultDTO.STATUS_UNAUTH);}LoginInitUtils.afterLogin(false,hreq,hres,user);chain.doFilter(req, resp);return;} catch (Exception e) {ApiResultDTO<String> apiResult=null;if(e instanceof BusinessException) {BusinessException businessException = (BusinessException) e;apiResult = ApiResultDTO.failed(businessException.getErrorCode(), businessException.getOriMsg());}else {apiResult = ApiResultDTO.failed(e.getMessage());}hres.setContentType("application/json;charset=UTF-8");hres.setHeader("Cache-Control", "no-store");hres.setHeader("Pragma", "no-cache");hres.setDateHeader("Expires", 0);hres.getWriter().write(new ObjectMapper().writeValueAsString(apiResult));hres.getWriter().flush();hres.getWriter().close();}}private String getCookieByCookieName(String cookieName,HttpServletRequest hreq) {Cookie[] cookies = hreq.getCookies();if(cookies!=null){for(Cookie cookie:cookies){if(cookieName.equalsIgnoreCase(cookie.getName())){return cookie.getValue();}}}return null;}
}
对内API过滤器
public class _APIFilter implements Filter {private Logger logger=LogManager.getLogger(this.getClass()); private ICachedTokenService tokenService;public _APIFilter(ICachedTokenService tokenService) {super();this.tokenService = tokenService;}@Overridepublic void init(FilterConfig arg0) throws ServletException {}@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {HttpServletRequest hreq = (HttpServletRequest) req;HttpServletResponse hres = (HttpServletResponse) resp;try{Utils.passOverByIp(hreq.getRemoteAddr());// logger.error("--------------------------_APIFilter["+hreq.getRequestURL()+"]开始--------------------------");AccessTokenUser user = null;String access_token=hreq.getParameter("access_token");if(StringUtils.isBlank(access_token)){access_token= hreq.getHeader("access_token");}//根据访问令牌获取用户if(StringUtils.isNotBlank(access_token)){try {String token=access_token;user = ThreadLocalCache.fetchAPIData("AccessTokenUser."+token+",true",() -> {ApiResultDTO<AccessTokenUser> tokenUserResp=  tokenService.getAccessTokenUserByAccessToken(token, true);if(tokenUserResp.isSuccessed()) {return tokenUserResp;}else {String errorMsg = "访问令牌服务发生错误,错误码:"+tokenUserResp.getStatus()+",错误信息:"+tokenUserResp.getStatusMsg();logger.error(errorMsg);throw new RuntimeException(errorMsg);}});} catch (Exception e) {e.printStackTrace();user=null;}if(user==null) logger.error("--------------------------_APIFilter["+hreq.getRequestURL()+"]access_token["+access_token+"]获取用户结果"+user+"--------------------------");}//根据内部令牌获取用户if(user==null) {String inner_token=hreq.getParameter("inner_token");if(StringUtils.isBlank(inner_token)){inner_token = hreq.getHeader("inner_token");}if(StringUtils.isBlank(inner_token)) throw new RuntimeException("未找到访问令牌");String token=inner_token;user=ThreadLocalCache.fetchAPIData(null,()->{return tokenService.verifyTokenAndGetUser(token);},"验证访问令牌错误,");if(user==null) logger.error("--------------------------_APIFilter["+hreq.getRequestURL()+"]inner_token["+inner_token+"]获取用户结果"+user+"--------------------------");}LoginInitUtils.afterLogin(false,hreq,hres,user);chain.doFilter(req, resp);return;} catch (Exception e) {e.printStackTrace();ApiResultDTO<String> apiResult=ApiResultDTO.failed(e.getMessage());hres.setContentType("application/json;charset=UTF-8");hres.setHeader("Cache-Control", "no-store");hres.setHeader("Pragma", "no-cache");hres.setDateHeader("Expires", 0);hres.getWriter().write(new ObjectMapper().writeValueAsString(apiResult));hres.getWriter().flush();hres.getWriter().close();}}}
public ApiResultDTO<AccessTokenUser> verifyTokenAndGetUser(String inner_token) {Map<String,String> claims=JWTUtils.verifyTokenAndGetClaims(inner_token);AccessTokenUser user=null;if(claims.get("user")!=null) {user=JsonConverter.jsonStrToObject(claims.get("user"), AccessTokenUser.class);}return ApiResultDTO.success(user);}
//将inner_token 转化为用户信息
public static Map<String,String> verifyTokenAndGetClaims(String jwt_token) {JWT jwt=JWT.create();//jwt.setHeader(JWTHeader.TYPE, "JWT");//默认值jwt.setHeader(JWTHeader.ALGORITHM, "HS256");jwt.setSigner(JWTSignerUtil.createSigner("HS256", SECRET));try {jwt.parse(jwt_token);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("校验jwt_token令牌失败");}if(!jwt.verify()) {throw new RuntimeException("无效的jwt_token");}Map<String,String> result = new HashMap<String,String>();JSONObject jo=jwt.getPayloads();if(jo==null||jo.size()==0) {return result;}for (Map.Entry<String,Object> d: jo.entrySet()) {if(d.getValue()==null) {continue;}result.put(d.getKey(), d.getValue().toString());}return result;}

配置拦截器

@Configuration
public class FiltersConfiguration {@Autowiredprivate ICachedTokenService tokenService;//前后端交互处理-拦截所有api访问请求@Beanpublic FilterRegistrationBean<APIFilter> apiFilterRegistrationBean() {FilterRegistrationBean<APIFilter> registrationBean = new FilterRegistrationBean<APIFilter>();registrationBean.setFilter(new APIFilter(tokenService));registrationBean.addUrlPatterns("/api/*");registrationBean.setOrder(5);return registrationBean;}//前后端交互处理-拦截所有_api访问请求@Beanpublic FilterRegistrationBean<_APIFilter> _apiFilterRegistrationBean() {FilterRegistrationBean<_APIFilter> registrationBean = new FilterRegistrationBean<_APIFilter>();registrationBean.setFilter(new _APIFilter(tokenService));registrationBean.addUrlPatterns("/_api/*");registrationBean.setOrder(6);return registrationBean;}
}

清除缓存

基础数据定义的一些资源变更,需要同步清除其他项目本地缓存

配置清除缓存过滤器
	//处理基础数据变更后通知各系统清空本系统的基础数据的缓存@Beanpublic FilterRegistrationBean<FireSysDataChangedEventFilter> fireSysDataChangedEventFilterRegistrationBean() {FilterRegistrationBean<FireSysDataChangedEventFilter> registrationBean = new FilterRegistrationBean<FireSysDataChangedEventFilter>();registrationBean.setFilter(new FireSysDataChangedEventFilter(fireSysDataChangedEventService));registrationBean.addUrlPatterns("/api/*");registrationBean.setOrder(5);return registrationBean;}
定义过滤器
public class FireSysDataChangedEventFilter implements Filter {private Logger logger = LoggerFactory.getLogger(this.getClass());private IFireSysDataChangedEventService fireSysDataChangedEventService;public FireSysDataChangedEventFilter(IFireSysDataChangedEventService fireSysDataChangedEventService) {super();this.fireSysDataChangedEventService = fireSysDataChangedEventService;}@Overridepublic void init(FilterConfig arg0) throws ServletException {}@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {try {chain.doFilter(req, resp);fireSysDataChangedEventIfNecessary(req);}finally {SysDataChanged.reset();}}private void fireSysDataChangedEventIfNecessary(ServletRequest req) {try {if(SysDataChanged.isChanged()) {HttpServletRequest hreq = (HttpServletRequest)req;String uri = hreq.getRequestURI();logger.info("完成请求{}后,基础数据有变更,需要向其他系统发出清除缓存的消息",uri);fireSysDataChangedEventService.sysDataChanged();}}catch(Exception e) {e.printStackTrace();logger.error("fireSysDataChangedEventIfNecessary错误{}",e.getMessage());}	}
}
定义清除缓存服务
public interface IFireSysDataChangedEventService {/*** 基础数据发生变更*/void sysDataChanged();}
@Service
@ConfigurationProperties(prefix="docin-sys.config",ignoreUnknownFields=true)
public class FireSysDataChangedEventService implements IFireSysDataChangedEventService  {private Logger logger = LoggerFactory.getLogger(this.getClass());@Autowiredprivate ISysDataVersionService sysDataVersionService;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate AsyncTaskComponent asyncTaskComponent;//这里的url是再配置文件配置的//清理缓存urlsprivate Map<String, List<String>> clearcacheurls = new HashMap<>();public void setClearcacheurls(Map<String, List<String>> clearcacheurls) {this.clearcacheurls = clearcacheurls;}@SuppressWarnings("unchecked")@Overridepublic void sysDataChanged() {long lastTimestamp = System.currentTimeMillis();//更新系统版本时间戳sysDataVersionService.updateLastTimestampOfSysData(lastTimestamp);logger.info("成功更新系统版本时间戳为{}",lastTimestamp);if(MapUtils.isEmpty(clearcacheurls)) return;for (Map.Entry<String,List<String>> e: clearcacheurls.entrySet()) {asyncTaskComponent.runTaskInThreadPool((d)->{String name=(String)d.get("name");List<String> urls=(List<String>)(d.get("urls"));for (String url : urls) {try {restTemplate.getForObject(url, String.class);logger.info("向服务["+name+"].["+url+"]发送清理缓存请求成功");} catch (Exception e2) {logger.error("向服务["+name+"].["+url+"]发送清理缓存请求失败,",e2);}}return null;}, Utils.buildMap("name",e.getKey(),"urls",e.getValue()));}}}
docin-sys.config.clearcacheurls.docin-xfxt[0]=http://localhost:8088/docin-xfxt/syscache/clear
docin-sys.config.clearcacheurls.docin-xfxt[1]=http://localhost:8088/docin-xfxt/syscache/clear
docin-sys.config.clearcacheurls.docin-sys[0]=http://localhost:8088/docin-sys/syscache/clear
docin-sys.config.clearcacheurls.docin-sys[1]=http://localhost:8088/docin-sys/syscache/clear
docin-sys.config.clearcacheurls.docin-portal[0]=http://localhost:8088/docin-portal/syscache/clear
docin-sys.config.clearcacheurls.docin-stat[0]=http://localhost:8088/docin-portal/syscache/clear
docin-sys.config.clearcacheurls.hlw-xfxt[0]=http://localhost:8089/hlw-xfxt/syscache/clear
docin-sys.config.clearcacheurls.hlw-sys[0]=http://localhost:8089/hlw-sys/syscache/clear
docin-sys.config.clearcacheurls.docin-xf-exchange[0]=http://localhost:8080/docin-xf-exchange/syscache/clear
具体清除缓存请求接口
@Api(value="公共基础请求-基础数据缓存处理",tags="公共基础请求")
@RestController
@RequestMapping(value="/syscache")
public class SysDataCacheController {@Autowiredprivate CronClearSysDataCacheJob cronClearSysDataCacheJob;@ApiOperation(value="清理基础数据缓存", httpMethod="GET")@RequestMapping(value="/clear", method=RequestMethod.GET)public ApiResultDTO<RequestMsgTempVO> clearSyscache(HttpServletRequest request){return RestAPITemplate.restapi(()->{cronClearSysDataCacheJob.refreshCache();return null;});}}
清除本地缓存
	@Autowiredprivate ISysDataVersionService sysDataVersionService;//本地所获得基础数据最后更新时间戳private volatile long lastSysTimestamp = -1L;private volatile boolean refreshing=false;@Async("taskExecutor")//使用线程池 启动public void refreshCache() {logger.info("定时刷新令牌任务启动");if(this.refreshing) {logger.error("之前刷新任务还在堵塞中....");return;}try {this.refreshing = true;long lastSysTimestampOfServer = sysDataVersionService.getLastTimestampOfSysData();if(this.lastSysTimestamp!=lastSysTimestampOfServer) {this.lastSysTimestamp = lastSysTimestampOfServer;SysDataCacheAspect.clearCache();logger.warn("本地基础数据缓存已经清理,清理后本地基础数据版本为{}",lastSysTimestamp);Thread.sleep(5000);//防止攻击}else {logger.info("本地基础数据缓存的版本与基础数据服务一致,无需清理,本地基础数据版本为{}",lastSysTimestamp);}}catch (InterruptedException e) {e.printStackTrace();}finally {this.refreshing=false;}}
缓存逻辑
@Aspect   //定义一个切面
@Configuration
public class SysDataCacheAspect {private static Logger logger = LogManager.getLogger(SysDataCacheAspect.class);private static final  Map<String,Boolean> cacheFileNames = new ConcurrentHashMap<String, Boolean>();private static LoadingCache<String,Object> cache = null;static {// CacheLoader 初始化CacheLoader<String, Object> cacheLoader = new CacheLoader<String, Object>() {@Override// load方法的作用是在通过get方法从LoadingCache获取不到值时去加载该值并放入缓存。public Object load(String key) throws Exception {return null;}};cache = CacheBuilder.newBuilder()// 设置容量大小.maximumSize(80000)//默认一天后过期.expireAfterWrite(10, TimeUnit.DAYS).removalListener(new RemovalListener<String, Object>() {@Overridepublic void onRemoval(RemovalNotification<String, Object> notification) {if(notification.getValue()!=null && notification.getValue() instanceof CacheFile) {CacheFile cacheFile = (CacheFile)notification.getValue();removeCacheFile(cacheFile.fileName);}}})// 加载器配置.build(cacheLoader);}private String normalizedArgsStr(Object[] args){if(args==null || args.length==0) {return "";}Object[] normalizedArgs = new Object[args.length];if(args!=null) {for(int i=0;i<args.length;i++) {Object arg = args[i];if(arg instanceof AccessTokenUser) {AccessTokenUser user = (AccessTokenUser)arg;normalizedArgs[i]= user.getUserId();}else {normalizedArgs[i]=arg;}}}return JsonConverter.toJsonStr(normalizedArgs);}@Around("execution(* (@com.xysd.bizbase.annotation.SysDataCache *).*(..)) || execution(@com.xysd.bizbase.annotation.SysDataCache * *(..))")public Object process(ProceedingJoinPoint point) throws Throwable {String className = point.getSignature().getDeclaringTypeName();String methodName = point.getSignature().getName();Object[] args = point.getArgs();String key = className+"_$_"+methodName+"_$_"+(normalizedArgsStr(args));Object cached = cache.getIfPresent(key);if(methodName.endsWith("_dontCache")){return point.proceed(args);}if(cached!=null) {if(cached instanceof CacheFile) {CacheFile cachedFile = (CacheFile)cached;Object cachedData =  readCachedData(cachedFile);if(cachedData==null) {//读取缓存失败return point.proceed(args);}else {return cachedData;}}else {return cached;}}else {cached = point.proceed(args);if(cached instanceof ApiResultDTO){if(((ApiResultDTO<?>) cached).getData() == null) return cached;}if(cached!=null) {try {CacheFile cachedFile = cacheToDiskIfNecessary(cached);if(cachedFile!=null) {cache.put(key, cachedFile);}else {cache.put(key, cached);}}catch(Exception e) {logger.error("缓存失败,失败信息{}",e.getMessage());e.printStackTrace();}}return cached;}}private Object readCachedData(CacheFile cachedFile) {String fileName = cachedFile.getFileName();String absolutePath = getAbsoluteCacheFilePath(fileName);File f = new File(absolutePath);InputStream in = null;ObjectInputStream oin = null;try {in = new FileInputStream(f);oin = new ObjectInputStream(in);Object cachedData = oin.readObject();return cachedData;}catch(Exception e) {logger.error("读取缓存序列化文件失败,失败信息:{}",e.getMessage());e.printStackTrace();return null;}finally {Utils.clean(in,oin);}}/*** 当value序列化后占用字节大于50K时写入磁盘进行缓存* @param value* @return*/private CacheFile cacheToDiskIfNecessary(Object value) {int cachThreadshold = 50*1024;ByteArrayOutputStream bos = null ; ObjectOutputStream oos = null;try {bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(value);oos.flush();byte[] byteArray = bos.toByteArray();if(byteArray!=null && byteArray.length>cachThreadshold) {return buildCacheFile(byteArray);}else {return null;}}catch(Exception e) {throw new RuntimeException(e);}finally {Utils.clean(bos,oos);}}private CacheFile buildCacheFile(byte[] byteArray) {String fileName = "syscachefile_"+Utils.getUUID("");String absolutePath = getAbsoluteCacheFilePath(fileName);File f = new File(absolutePath);OutputStream out = null;try {if(!f.getParentFile().exists()) {f.getParentFile().mkdirs();}out = new FileOutputStream(f);out.write(byteArray);out.flush();cacheFileNames.put(fileName, true);return new CacheFile(fileName);}catch(Exception e) {throw new RuntimeException(e);}finally {Utils.clean(out);}}private static String getAbsoluteCacheFilePath(String fileName) {String sysCacheBaseDir = Utils.getTmpDirRoot()+"/sysDataCache";return sysCacheBaseDir+"/"+fileName;}public static void removeCacheFile(String fileName) {if(StringUtils.isNoneBlank(fileName)) {cacheFileNames.remove(fileName);String absolutePath = getAbsoluteCacheFilePath(fileName);File f = new File(absolutePath);try {if(f.exists() && f.isFile()) {f.delete();}}catch(Exception e) {//删除失败不做任何处理e.printStackTrace();}}}/*** 清空缓存*/public static final void clearCache() {for(String fileName:cacheFileNames.keySet()) {removeCacheFile(fileName);}cacheFileNames.clear();cache.invalidateAll();}public static class CacheFile implements Serializable {private static final long serialVersionUID = -6926387004863371705L;private String fileName;public CacheFile(String fileName) {super();this.fileName = fileName;}public String getFileName() {return fileName;}}
}
拦截器

Hibernate的拦截器 监听实体变化

public class SysEntityUpdateListener extends EmptyInterceptor {/*** */private static final long serialVersionUID = -7428554904158765594L;@Overridepublic void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {super.onDelete(entity, id, state, propertyNames, types);SysDataChanged.changed();}@Overridepublic boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,String[] propertyNames, Type[] types) {SysDataChanged.changed();return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);}@Overridepublic boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {SysDataChanged.changed();return super.onSave(entity, id, state, propertyNames, types);}@Overridepublic void postFlush(Iterator entities) {super.postFlush(entities);}@Overridepublic int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,String[] propertyNames, Type[] types) {return super.findDirty(entity, id, currentState, previousState, propertyNames, types);}@Overridepublic void onCollectionRemove(Object collection, Serializable key) throws CallbackException {SysDataChanged.changed();super.onCollectionRemove(collection, key);}@Overridepublic void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {SysDataChanged.changed();super.onCollectionUpdate(collection, key);}}
记录是否要清理缓存
public class SysDataChanged {private static final ThreadLocal<Boolean> store = new ThreadLocal<Boolean>();/*** 当前线程已经更改过基础数据*/public static final void changed() {store.set(true);}/*** 重置*/public static final  void reset() {store.set(false);}/*** 当前线程是否更改过基础数据* @return*/public static final  boolean isChanged() {return Boolean.TRUE.equals(store.get());}}

通过SysEntityUpdateListener监听实体变化,更改SysDataChanged.store.set(true)。当用户请求后端接口时,通过FireSysDataChangedEventFilter过滤器判断SysDataChanged.store.get()==true,从而触发restTemplate.getForObject(url, String.class)请求,更新各个项目本地的基础数据缓存SysDataCacheAspect.clearCache()。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/655306.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

echarts:获取省、市、区/县、镇的地图数据

目录 第一章 前言 第二章 获取地图的数据&#xff08;GeoJSON格式&#xff09; 2.1 获取省、市、区/县地图数据 2.2 获取乡/镇/街道地图数据 第一章 前言 需求&#xff1a;接到要做大屏的需求&#xff0c;其中需要用echarts绘画一个地图&#xff0c;但是需要的地图是区/县…

C语言系列-整数在内存中的存储大小端字节序

&#x1f308;个人主页: 会编程的果子君 ​&#x1f4ab;个人格言:“成为自己未来的主人~” 目录 整数在内存中的存储 大小端字节序和字节序判断 什么是大小端 为什么会有大小端 练习 整数在内存中的存储 在讲解操作符的时候&#xff0c;我们就讲过了下面的内容 整数的2…

高端车规MCU的破局之路

目录 1 低质量的无效内卷 2 高端车规MCU产品共性 2.1 支持标定测量 2.2 低延迟通信加速 2.3 完备的网络安全解决方案 2.4虚拟化 3 国产替代的囚徒困境 1 低质量的无效内卷 近几年&#xff0c;车规MCU国产替代的呼声此消彼长&#xff0c;但仍然集中在低端产品。 从产…

JavaSE-网络编程,正则表达式

1. 网络编程 1.1 概述 Java是 Internet 上的语言&#xff0c;它从语言级上提供了对网络应用程 序的支持&#xff0c;程序员能够很容易开发常见的网络应用程序。 Java提供的网络类库&#xff0c;可以实现无痛的网络连接&#xff0c;联网的底层 细节被隐藏在 Java 的本机安装系统…

鸿蒙首批原生应用!无感验证已完美适配鸿蒙系统

顶象无感验证已成功适配鸿蒙系统&#xff0c;成为首批鸿蒙原生应用&#xff0c;助力鸿蒙生态的快速发展。 作为全场景分布式操作系统&#xff0c;鸿蒙系统旨在打破不同设备之间的界限&#xff0c;实现极速发现、极速连接、硬件互助、资源共享。迄今生态设备数已突破8亿台&…

R语言【taxlist】——tax2traits():将分类信息设置为分类单元特征

Package taxlist version 0.2.4 Description 分类法分类可以包含在taxonRelations插槽提供的信息中的 taxlist 对象中。然而&#xff0c;对于统计分析来说&#xff0c;将这些信息插入到插槽taxonTraits中可能更方便。 Usage tax2traits(object, ...)## S3 method for class …

多openssl版本共存,如何再装一个openssl低版本

在编译安装TrinityCore的时候&#xff0c;碰到报错&#xff1a; 报错&#xff1a; CMake Error at cmake/macros/FindOpenSSL.cmake:579 (message): TrinityCore needs OpenSSL version 1.0 but found too new version . TrinityCore needs OpenSSL 1.0.x or 1.1.x to wor…

软考复习之数据结构篇

算法设计 迭代法&#xff1a;用于求方程的近似根。 1、若方程无解&#xff0c;则算法求出的近似根序列就不会收敛&#xff0c;迭代过程会变成死循环&#xff0c;因此在使用迭代算法前应先考查方程是否有解&#xff0c;并在程序中对迭代的次数给予限制。 2、方程虽有解&#…

OpenSSH 9.6/9.6p1 (2023-12-18)的发布说明(中文译文)

OpenSSH 9.6/9.6p1 (2023-12-18) OpenSSH 9.6 于 2023 年 12 月 18 日发布。相关镜像位于OpenSSH。OpenSSH 是 100% 完整的 SSH 协议 2.0 实现包括 sftp 客户端和服务器支持。 再次感谢 OpenSSH 社区的帮助,继续支持该项目&#xff0c;特别是那些将代码或补丁、报告的错误、…

第十一篇【传奇开心果系列】BeeWare的Toga开发移动应用示例:Briefcase和Toga 哥俩好

传奇开心果博文系列 系列博文目录BeeWare的Toga开发移动应用示例系列博文目录一、前言二、Briefcase和toga各自的主要功能分别介绍三、使用Toga 开发移动应用Briefcase工具是最佳拍档四、Briefcase搭档Toga创建打包发布联系人移动应用示例代码五、运行测试打包发布六、归纳总结…

二、Vue3文件目录介绍

node_modules: 项目的依赖库&#xff1b; src &#xff1a; 我们主要操作的地方&#xff0c;组件的增加、修改等都在这个文件夹里操作&#xff1b; assets: 放置静态资源&#xff0c;包括公共的 css 文件、 js 文件、iconfont 字体文件、img 图片文件 以及其他资源类文件。之所…

RabbitMQ之三种队列之间的区别及如何选型

目录 不同队列之间的区别 Classic经典队列 Quorum仲裁队列 Stream流式队列 如何使用不同类型的队列​ Quorum队列 Stream队列 不同队列之间的区别 Classic经典队列 这是RabbitMQ最为经典的队列类型。在单机环境中&#xff0c;拥有比较高的消息可靠性。 经典队列可以选…

数据库管理-第141期 DG PDB - Oracle DB 23c(20240129)

数据库管理141期 2024-01-29 第141期 DG PDB - Oracle DB 23c&#xff08;20240129&#xff09;1 概念2 环境说明3 操作3.1 数据库配置3.2 配置tnsname3.3 配置强制日志3.4 DG配置3.5 DG配置建立联系3.6 启用所有DG配置3.7 启用DG PDB3.8 创建源PDB的DG配置3.9 拷贝pdbprod1文件…

2023年算法CDO-CNN-BiLSTM-ATTENTION回归预测(matlab)

2023年算法CDO-CNN-BiLSTM-ATTENTION回归预测&#xff08;matlab&#xff09; CDO-CNN-BiLSTM-Attention切诺贝利灾难优化器优化卷积-长短期记忆神经网络结合注意力机制的数据回归预测 Matlab语言。 切诺贝利灾难优化器Chernobyl Disaster Optimizer (CDO)是H. Shehadeh于202…

薅运营商羊毛?封杀!

最近边小缘在蓝点网上看到一则消息 “浙江联通也开始严格排查PCDN和PT等大流量行为 被检测到可能会封停宽带”。 此前中国联通已经在四川和上海等多个省市严查家庭宽带 (部分企业宽带也被查) 使用 PCDN 或 PT&#xff0c;当用户的宽带账户存在大量上传数据的情况&#xff0c;中…

Jupyter notebook文件默认存储路径以及更改方法

目录 1、文件默认存储路径怎么查&#xff1f;2、文件默认存储路径怎么改&#xff1f; 转自&#xff1a;https://blog.csdn.net/fengyeer20120/article/details/109483362 初次使用Jupyter Notebook&#xff0c;确实好用啊&#xff01;但安装Anaconda后&#xff0c;打开Jupyter …

gorm框架之常用增删改查(CRUD)

最好的文档其实是官方的文档&#xff0c;大家可以参考这个文档链接&#xff0c;本文也只是个搬运工&#xff1a; GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly. 新建&#xff08;create&#xff09; 新建单条记录 一般新建记录…

cocos creator 调用预设体Prefab中的方法(调用另一个节点的方法)

调用预设体中的方法 通过cc.instantiate(this.star)创建这个预设体实例这个star预设体中添加了一个脚本组件star.ts 获取到这个脚本组件star.getComponent(‘star’).test()&#xff0c;并调用其中的test()方法同理可以用该方式像另一个节点中传值 //星星预设体property(cc.Pr…

[深度学习]paddleocrv4模型推理要比v3版本慢很多原因

请问为何 Mkldnn 在 ChineseV4 下运行会比 Onnx 和 Openblas 慢很多&#xff1f; 资料来源&#xff1a;https://github.com/sdcb/PaddleSharp/issues/75 qaqz111 commented on Dec 6, 2023 • edited 按 Readme 里面的说明来看&#xff0c;貌似 mkl 比 openblas 是要快的&…

【PostGIS】POSTGIS实现聚类统计提取外轮廓

项目需求根据某些条件进行聚类统计&#xff0c;然后返回聚类的外轮廓&#xff0c;这里主要用到POSTGIS的两个算法&#xff0c;一个是聚类统计功能&#xff0c;一个是提取外轮廓的功能。 1. 聚类统计 Postgis主要实现并提供了四种聚类方法&#xff0c;前两个为窗口函数&#x…