**

## springboot集成springSecurity,jwt实现授权,查看权限,获取用户信息;】
简单的springsecurity授权登录校验我就暂时不写了,博客太多了;
第一步:还是导入相关依赖;

<jwt依赖><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency><springsecurity依赖><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>

接下来就是书写实现springsecurity的那个自定义 UserDetails接口,这个很重要,没有这个,后面做不了那个权限分配,账号密码校验,角色分配;

import com.alibaba.fastjson.annotation.JSONField;
import com.lihua.pojo.entity.DtsAdminEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {private static final long serialVersionUID = 1905122041950251207L;private DtsAdminEntity adminEntity;private List<String> roleList;private List<Integer>  permission;@JSONField(serialize = false)private List<GrantedAuthority> authorities;public LoginUser(DtsAdminEntity adminEntity, List<Integer> permissionList, List<String> roleList) {this.adminEntity = adminEntity;this.permission = permissionList;this.roleList = roleList;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {authorities = new ArrayList<>();for (String roles : roleList) {authorities.add(new SimpleGrantedAuthority(roles));}for (Integer per  : permission) {authorities.add(new SimpleGrantedAuthority(per.toString()));}return authorities;}@Overridepublic String getPassword() {return new BCryptPasswordEncoder().encode(adminEntity.getPassword());}@Overridepublic String getUsername() {return this.adminEntity.getUsername();}@Overridepublic boolean isAccountNonExpired() {//帐号是不是没有过期return true;}@Overridepublic boolean isAccountNonLocked() { //是不是没有被锁定return true;}@Overridepublic boolean isCredentialsNonExpired() { //凭证是不是没有过期return true;}@Overridepublic boolean isEnabled() {  //是否可用return true;}
}

注意:DtsAdminEntity 是你自定义的那个用户信息类实体,这个里面最好包含那个用户名(账户名)username,密码(pssword),以及角色id,或者账号是否过期的标识,一般返回那个正确标识的那个结果;
接下来就就是你有哪些权限,这个最好是返回那个权限菜单的主键标识,方便你后面查表,获取权限列表;
 return new BCryptPasswordEncoder().encode(adminEntity.getPassword());其中这行代码相当关键,是你密码校验中的精髓,注意必须要满足那个springSecurity加密方式,不然你后面每次改了密码或者新增用户每次都会出现你的密码错误,拿不到那个令牌,导致你总是登录失败;
好了接下来就是比较重要的一个环节,注册登录,但是这里我就不弄那个注册了,密码一定要符合那个springsecurity那个加密方式,可以加盐,但是这里我就不做演示了;登录的代码:
控制层:

@CrossOrigin@PostMapping(value = "login")public ResponseResult login(@RequestBody MerberLoginVo merberLoginVo) {String token = dtsAdminService.login(merberLoginVo.getUsername(), merberLoginVo.getPassword());if (StringUtils.isEmpty(token)) {return ResponseResult.setResult(ResponseEnum.ERROR);}return ResponseResult.ok().data("token", token);}

这个service实现层代码:
    首先注入
    // 记住:这个是特别重要的,决定你能不能登录!
    @Autowired
    private AuthenticationManager authenticationManager;
    // 这个是把那个人信息放到那个redis缓存中,会过期的,所以想要在线时间长点,建议把那个jwt过期时间设置长点!
    @Autowired
    private RedisCache redisCache;

登录实现方法:

 @Overridepublic String login(String username, String password) {//使用Authentication的实现类Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);//手动调用方法去认证 他会自动调用UserDetailsService查 然后对比啥的Authentication authenticate = authenticationManager.authenticate(authentication);if (Objects.isNull(authenticate)) {//说明输入错误throw new RuntimeException("用户名或密码错误");}//拿到用户信息 然后生成jwt返回给前端,并且将用户的信息存入redis,这个其实就是UserDetails 也就是LoginUserLoginUser loginUser = (LoginUser) authenticate.getPrincipal();String userId = loginUser.getAdminEntity().getId().toString();String jwt = JwtUtil.createJwt(userId);//将用户信息直接存入redisredisCache.setCacheObject("login:" + userId, loginUser);return jwt;}

jwt工具类:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;/*** JWT工具类** @author THUNOEROBOT*/
public class JwtUtil {/*** 有效期为 60 * 60 *1000  一个小时*/public static final Long JWT_TTL = 24 * 60 * 60 * 1000L;/*** 设置秘钥明文*/public static final String JWT_KEY = "yunduo";public static String getUuid() {return UUID.randomUUID().toString().replace("-", "");}/*** 生成jtw* 设置过期时间** @param subject token中要存放的数据(json格式)* @return   jwt字符串*/public static String createJwt(String subject) {JwtBuilder builder = getJwtBuilder(subject, null, getUuid());return builder.compact();}private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if (ttlMillis == null) {ttlMillis = JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);return Jwts.builder().setId(uuid).setSubject(subject).setIssuer("yunduo").setIssuedAt(now).signWith(signatureAlgorithm, secretKey).setExpiration(expDate);}public static void main(String[] args) {String token = "输入你的幸运字符";Claims claims = parseJwt(token);}/*** 生成加密后的秘钥 secretKey** @return  secretKey*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");}/*** 解析** @param jwt jwt* @return 对象用户*/public static Claims parseJwt(String jwt) {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}}

redis缓存类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.*;
import java.util.concurrent.TimeUnit;/*** @author THUNOEROBOT*/
@Component
public class RedisCache
{@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值* @param timeout 时间* @param timeUnit 时间颗粒度*/public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @param unit 时间单位* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** @param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}/*** 删除集合对象** @param collection 多个对象* @return*/public long deleteObject(final Collection collection){return redisTemplate.delete(collection);}/*** 缓存List数据** @param key 缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long setCacheList(final String key, final List<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** @param key 缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet){BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);for (T t : dataSet) {setOperation.add(t);}return setOperation;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 缓存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap){if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** @param key Redis键* @param hKey Hash键* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** @param key Redis键* @param hKey Hash键* @return Hash中的对象*/public <T> T getCacheMapValue(final String key, final String hKey){HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 删除Hash中的数据** @param key* @param hkey*/public void delCacheMapValue(final String key, final String hkey){HashOperations hashOperations = redisTemplate.opsForHash();hashOperations.delete(key, hkey);}/*** 获取多个Hash中的数据** @param key Redis键* @param hKeys Hash键集合* @return Hash对象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 获得缓存的基本对象列表** @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(final String pattern){return redisTemplate.keys(pattern);}
}

redis序列化配置:

import com.lihua.utils.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @author THUNOEROBOT*/
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}
}redis序列化中使用的fastJson配置类import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.parser.ParserConfig;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;/*** Redis使用FastJson序列化** @author sg*/
public class FastJsonRedisSerializer<T> implements RedisSerializer<T>
{public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;private final Class<T> clazz;static{ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}public FastJsonRedisSerializer(Class<T> clazz){super();this.clazz = clazz;}@Overridepublic byte[] serialize(T t) throws SerializationException{if (t == null){return new byte[0];}return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}@Overridepublic T deserialize(byte[] bytes) throws SerializationException{if (bytes == null || bytes.length <= 0){return null;}String str = new String(bytes, DEFAULT_CHARSET);return JSON.parseObject(str, clazz);}}

测试一下,验证一下:


拿到了我们的token,接下来就是书写那个配置,这个是整个项目的核心,缺少这个,项目是不完美的,而且你的项目有可能是启动失败的,会突然跑不起来!!!

接下来讲下如何配置

import com.lihua.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate AuthenticationEntryPoint authenticationEntryPoint;@Autowiredprivate AccessDeniedHandler accessDeniedHandler;token过滤配置注入,注意这个时候的@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and()//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers("/**/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overridepublic void configure(WebSecurity web) {web.ignoring().antMatchers("/css/**","/js/**","/index.html","/img/**","/fonts/**","/favicon.ico","/verifyCode");}}

接下来就是书写那个token过滤器,注意没有这个,你无法在实现上下文携带token操作,无法在前后端项目中流畅的操作

import com.lihua.config.RedisCache;
import com.lihua.jwt.JwtUtil;
import com.lihua.jwt.LoginUser;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;/*** @author*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//我们先拿到请求头中的tokenString token = request.getHeader("token");if(StringUtils.isBlank(token)){//说明没有携带token 那么直接放行 之后的过滤器肯定会报错,那么就说明用户没有登录filterChain.doFilter(request,response);return;}//解析tokenString userid;try {Claims claims = JwtUtil.parseJwt(token);userid  = claims.getSubject();} catch (Exception e) {e.printStackTrace();//就说明token失效了 或者是token无效throw new RuntimeException("token无效");}//从redis中拿到用户的信息,给SecurityContextHolder设置上下文LoginUser loginUser = redisCache.getCacheObject("login:" + userid);if(Objects.isNull(loginUser)){throw new RuntimeException("用户未登录");}//存入SecurityContextHolder上下文当中  注意 这里必须得使用三个参数的authentication//第三个参数则为权限Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authentication);//放行filterChain.doFilter(request,response);}
}

接下来就是自定义配置那个未授权的配置了,不可能使用那个原生的springsecurity的未授权页面,那样就得你很不专业,就像我昨天说这个框架---》春季安全框架,是没错,但是你好不专业!

import com.alibaba.fastjson.JSON;
import com.lihua.result.ResponseEnum;
import com.lihua.result.ResponseResult;
import com.lihua.utils.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e)  {response.setStatus(HttpStatus.FORBIDDEN.value());ResponseResult result = ResponseResult.setResult(ResponseEnum.NO_PERMISSIONS);WebUtils.renderString(response, JSON.toJSONString(result));}
}
import com.alibaba.fastjson.JSON;
import com.lihua.result.ResponseEnum;
import com.lihua.result.ResponseResult;
import com.lihua.utils.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @author THUNOEROBOT*/
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {Logger logger = LoggerFactory.getLogger(getClass());@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {//401 表示没有授权response.setStatus(HttpStatus.UNAUTHORIZED.value());ResponseResult result = ResponseResult.setResult(ResponseEnum.NO_AUTHORIZATION);WebUtils.renderString(response, JSON.toJSONString(result));}
}

接下来就是讲讲配置文件的作用了;我不可能写份代码给你,然后看了一脸懵逼!这是写的啥垃圾文章!!!
第一个地方,解决你前端老是报跨域啊,哎哟喂,怎么又跨域啦,头疼!!!!

第二个疑惑,就是你的token是怎么来的,以及密码校验

我们的前后端分离项目,肯定会涉及静态资源的放行对不???

整个流程就是这样了,当然如何获取个人信息,那就去看看如何解析jwt了!
好了跟大家说say good bye!嘿嘿

springboot集成springSecurity,jwt实现前后端分离相关推荐

  1. Java权限管理|基于springBoot+springSecurity+jwt实现前后端分离用户权限认证

    基于springBoot+springSecurity+jwt实现前后端分离用户权限认证 1. 项目说明   主要基于前后端分离情况下用户权限认证, 当用户登录认证成功后,每个用户会获取到自己的tok ...

  2. 【Vue+SpringBoot】超详细!一周开发一个SpringBoot + Vue+MybatisPlus+Shiro+JWT+Redis前后端分离个人博客项目!!!【项目完结】

    项目目录 资源准备 前后端分离项目 技术栈 Java后端接口开发 1.前言 2.新建Springboot项目 3.整合mybatis plus 3.统一结果封装 4.整合shiro+jwt,并会话共享 ...

  3. 计算机毕业设计-springboot企业考勤管理系统(前后端分离)员工考勤管理系统-公司日常管理系统java代码

    计算机毕业设计-springboot企业考勤管理系统(前后端分离)员工考勤管理系统-公司日常管理系统java代码 注意:该项目只展示部分功能,如需了解,联系咨询即可. 作者:IT跃迁谷 1.开发环境 ...

  4. SpringBoot+LayUI+MybatisPlus+Echarts图表 前后端分离 实现数据统计功能

    前言: 小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java快一年时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师. 首先给各位粉丝朋友 ...

  5. Springboot+vue 社团管理系统(前后端分离)

    Springboot+vue 社团管理系统(前后端分离) zero.项目功能设计图 一.数据库设计(项目准备) 1.建表 2.表目录 二.前端编写(vue) 1.搭建Vue框架 2.放入静态资源(as ...

  6. SSM+JWT实现前后端分离的token验证

    SSM+JWT实现前后端分离的token验证 前言 什么是JWT 基于Token的验证流程 JWT的Token实现 后端部分 前端部分 测试 项目完整地址 前言 以前写的web项目都是没有前后端分离的 ...

  7. 毕设:基于SpringBoot+Vue 实现云音乐(前后端分离)

    文章目录 一.简介 2.项目介绍 二.功能 2.功能介绍 三.核心技术 1.系统架构图 2.技术选型 五.运行 3.截图 前端界面 后台管理界面 总结 1.完整工程 2.其他 一.简介 2.项目介绍 ...

  8. springboot jwt token前后端分离_基于Spring Boot+Spring Security+JWT+Vue前后端分离的开源项目...

    一.前言 最近整合Spring Boot+Spring Security+JWT+Vue 完成了一套前后端分离的基础项目,这里把它开源出来分享给有需要的小伙伴们 功能很简单,单点登录,前后端动态权限配 ...

  9. springboot jwt token前后端分离_实战:十分钟实现基于JWT前后端分离的权限框架

    前言 面试过很多Java开发,能把权限这块说的清楚的实在是不多,很多人因为公司项目职责问题,很难学到这类相关的流程和技术,本文梳理一个简单的场景,实现一个基于jwt前后端分离的权限框架. 简易流程 登 ...

最新文章

  1. mysql association_mybatis association 一对一
  2. 台式机计算机删除,电脑c盘满了怎么清理 电脑c盘可以删除哪些文件
  3. Angular.js中使用$watch监听模型变化
  4. iti axi dsp_ITI的完整形式是什么?
  5. .Net读取rss的两种方法
  6. Printer Processor 导致的一个问题
  7. 【codevs2485】七夕祭(贪心,环形纸牌均分)
  8. java类后面的尖括号_泛型 - Java中的T(尖括号)是什么意思?
  9. 【新技术】 移动支付过程中的NFC技术
  10. oracle全库导入 imp,imp导入全数据库
  11. Mac系统如何制作Mac U盘启动盘(更新至mac 12.6)
  12. 开源地图平台 Mapbender
  13. Android按钮按下的时候改变颜色/图片
  14. 树莓派与matlab联动并安装opencv
  15. 分享本电子书Sql Server 20008 internals
  16. 不用修改flash源文件,给.swf 加链接地址方法
  17. 大前端进阶!NodeJS、Npm、Es6、Babel、Webpack、模块化开发
  18. OPPO折叠屏发布后,外媒把“矛头”对准三星,Find N和Fold 3哪个好?
  19. python基础教程(第3版) pdf,python手册中文版第四版
  20. HR在线招人,快甩简历啦

热门文章

  1. x265常用编码参数
  2. 数据集:银行客户信息
  3. 一图掌握ISACA五大资格证书体系
  4. MATLAB实现数字滤波器的频带变换
  5. Mac 使用Charles后,退出Charles后,不能浏览网页,提示:未连接到互联网代理服务器出现问题,或者地址有误。
  6. HDUOJ 6608 Fansblog
  7. 德州仪器TM4C123GXL从入手到亮灯-开发环境配置
  8. 金额大小写转化、阿拉伯数字转大写数字,大写数字转阿拉伯数字
  9. 上帝视角学JAVA- 基础08-类06【2021-08-07】
  10. html5 车牌识别,深度学习实现车牌识别