SpringSecurity中授权时fastjson序列化问题

2023-11-12

最近在复习Spring Security,复习的鉴权的时候出现问题。26.封装权限信息_哔哩哔哩_bilibili

如果是从B站中看到,直接说问题可能出现的原因:可能是private List<String> authorities;中的权限信息命名不规范,去掉get,A变小写。如果要细看原因请往下看。

 下图是代码中aaaaa是我测试的权限信息集合,故意命名写的不规范,才知道原因。

问题场景:使用Spring Security模拟授权的时候,手动存入几个权限信息,然后正确的访问时出现了问题。

重要的事情放前面说:如果不配置权限集合如果不加@JSONField(serialize = false)注解,解析的时候会报错。

 UserDetailServiceImpl.java   UserDetailsService实现类

@Service
public class UserDetailServiceImpl implements UserDetailsService {


    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //查询用户信息

        LambdaQueryWrapper<User> queryChainWrap = new LambdaQueryWrapper<>();
        queryChainWrap.eq(!Objects.isNull(username), User::getUserName, username);
        User user = userMapper.selectOne(queryChainWrap);
        // 如果没有查询到用户就抛出异常
        if (Objects.isNull(user)) {
            throw new RuntimeException("用户名或密码错误");
        }

        //TODO 查询对应的权限信息
        ArrayList<String> list = new ArrayList<>(Arrays.asList("test", "admin"));

        // 把数据封装成UserDetails返回
        return new LoginUser(user, list);
//        return new LoginUser(user);
    }
}

LoginServiceImpl.java   自定义登录接口实现类

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private AuthenticationManager authenticationManager;


    @Autowired
    private RedisCache redisCache;

    @Override
    public ResponseResult login(User user) throws Exception {
        //AuthenticationManager authenticate进行用户认证
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
//        authenticate.getPrincipal()
        // 如果认证没有通过,给出对应的提示
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("登录失败");
        }
        // 如果认证通过了,使用userid生成jwt jwt存入ResponseResult返回
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getId().toString();
        String jwt = JwtUtil.createJWT(userId);

        Map<String, String> map = new HashMap<>();
        map.put("token", jwt);
        // 把完整的用户信息存入redis userid作为key
        redisCache.setCacheObject(SystemConstants.LOGIN_TOKEN_PREFIX + userId, loginUser);
        return new ResponseResult(200, "登录成功", map);
    }

    @Override
    public ResponseResult logout() {
        // 获取SecurityContextHolder中的用户id
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();

        Long userId = loginUser.getUser().getId();
        // 删除redis中的值
        redisCache.deleteObject(SystemConstants.LOGIN_TOKEN_PREFIX + userId);
        return new ResponseResult(200, "注销成功");
    }
}

JwtAuthenticationTokenFilter.java   自定义过滤器

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {


    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AuthenticationManager authenticationManager;

    @SneakyThrows(value = {RuntimeException.class, ArrayIndexOutOfBoundsException.class, Exception.class})
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 获取token
        String token = request.getHeader("token");
        // token为内容为空或者不以login:开头直接放行
        if (!StringUtils.hasText(token)) {
            // 放行
            filterChain.doFilter(request, response);
            return;
        }
        // 解析token获取其中的userId
        String userId;
        try {
            userId = JwtUtil.parseJWT(token).getSubject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("token非法");
        }
        // 从redis中获取用户信息
        String redisKey = SystemConstants.LOGIN_TOKEN_PREFIX + userId;
        LoginUser loginUser = redisCache.getCacheObject(redisKey);
        if (Objects.isNull(loginUser)) {
            throw new RuntimeException("用户未登录");
        }
        // 存入SecurityContextHolder
        // TODO 获取权限信息封装到Authentication
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        // 这里不知道为什么加这句,导致进行验证,走了后续过滤器,但是我发送的测试请求是带token的get请求,
        // 但是我的数据是从redis中获取,密码是加密后的,导致二次加密后,密码不一致
//        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);

        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        // 放行
        filterChain.doFilter(request, response);
    }
}

 待测试的Controller

 LoginUser.java   UserDetails实现类

@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {

    private User user;

    private List<String> permission;


    @JSONField(serialize = false)
//    @JsonIgnore
//    @JsonIgnoreProperties
    private List<GrantedAuthority> aaaaa;

//    @JSONField(serialize = false)
//    private List<String> authorities;

    public LoginUser(User user, List<String> permission) {
        this.user = user;
        this.permission = permission;
    }

    public LoginUser(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 把permission中String类型的去啊年信息封装成SimpleGrantedAuthority对象
        if (Objects.isNull(aaaaa)) {
            synchronized (this) {
                if (Objects.isNull(aaaaa)) {
                    aaaaa
                            = permission.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
                }
            }
        }
        return aaaaa;
//        ArrayList<GrantedAuthority> list = new ArrayList<>();
//        list.add(new SimpleGrantedAuthority("Powerveil"));
//        return list;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUserName();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

 直接看结果

 没有任何输出

看一下idea的console

2023-06-18 18:46:34.557 ERROR 21216 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

com.alibaba.fastjson.JSONException: autoType is not support. org.springframework.security.core.authority.SimpleGrantedAuthority
	at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:830) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:596) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:226) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:222) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseArray(DefaultJSONParser.java:716) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.serializer.CollectionCodec.deserialze(CollectionCodec.java:120) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:78) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseField(JavaBeanDeserializer.java:911) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:656) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:226) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:222) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:357) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1325) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.deserializer.JavaObjectDeserializer.deserialze(JavaObjectDeserializer.java:45) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:630) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:354) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:258) ~[fastjson-1.2.33.jar:na]
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:471) ~[fastjson-1.2.33.jar:na]
	at com.powerveil.utils.FastJsonRedisSerializer.deserialize(FastJsonRedisSerializer.java:56) ~[classes/:na]
	at org.springframework.data.redis.core.AbstractOperations.deserializeValue(AbstractOperations.java:335) ~[spring-data-redis-2.5.1.jar:2.5.1]
	at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:61) ~[spring-data-redis-2.5.1.jar:2.5.1]
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:222) ~[spring-data-redis-2.5.1.jar:2.5.1]
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:189) ~[spring-data-redis-2.5.1.jar:2.5.1]
	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:96) ~[spring-data-redis-2.5.1.jar:2.5.1]
	at org.springframework.data.redis.core.DefaultValueOperations.get(DefaultValueOperations.java:53) ~[spring-data-redis-2.5.1.jar:2.5.1]
	at com.powerveil.utils.RedisCache.getCacheObject(RedisCache.java:78) ~[classes/:na]
	at com.powerveil.filter.JwtAuthenticationTokenFilter.doFilterInternal(JwtAuthenticationTokenFilter.java:61) ~[classes/:na]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar:5.3.7]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar:5.3.7]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar:5.3.7]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) ~[spring-security-web-5.5.0.jar:5.5.0]
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.3.7.jar:5.3.7]
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.3.7.jar:5.3.7]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.7.jar:5.3.7]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar:5.3.7]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.7.jar:5.3.7]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar:5.3.7]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.7.jar:5.3.7]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar:5.3.7]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_321]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_321]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at java.lang.Thread.run(Thread.java:750) [na:1.8.0_321]

错误日志多不要害怕

 autoType is not support   不支持自动类型

看下面的错误

RedisCache.java是一个自定义的Redis工具类

原来是redis取出数据出现问题,看一下redis中存储的数据。

{
  "@type": "com.powerveil.domain.LoginUser",
  "accountNonExpired": true,
  "accountNonLocked": true,
  "authorities": [
    {
      "@type": "org.springframework.security.core.authority.SimpleGrantedAuthority",
      "authority": "test"
    },
    {
      "@type": "org.springframework.security.core.authority.SimpleGrantedAuthority",
      "authority": "admin"
    }
  ],
  "credentialsNonExpired": true,
  "enabled": true,
  "password": "$2a$10$4MzpJkpyo2gywu5B/b6zEO3gfyYqcEN.6PG5wEpcb9nASzPddq7fu",
  "permission": [
    "test",
    "admin"
  ],
  "user": {
    "delFlag": 0,
    "email": "zcuishuai@yeah.net",
    "id": 1,
    "nickName": "Powerveil",
    "password": "$2a$10$4MzpJkpyo2gywu5B/b6zEO3gfyYqcEN.6PG5wEpcb9nASzPddq7fu",
    "phonenumber": "123456789",
    "sex": "0",
    "status": "0",
    "userName": "Powerveil",
    "userType": "1"
  },
  "username": "Powerveil"
}

看到redis数据,怎么这么多字段

我自定义了只有三个字段

user

permission

aaaaa

 user,permisssion都看到出来,但是我的aaaaa怎么没有了,正常,因为使用了@JSONField(serialize = false)注解,不会写入redis中。

postman返回的结果

上面是我第一次遇到的情况,以下是其他测试情况,看完你就知道原因了。

2.将getAuthorities方法的返回值设为null其他不变。

redis中的结果 

发现authorities消失了

数据可以正常解析

但是结果403,但是也正常,因为鉴权的方法的返回值是null。

3.添加authorities字段

 方法正常重写

查看redis数据

发现authorities字段生成

redis数据解析错误

 postman返回的结果

4.给authorities字段加上@JSONField(serialize = false)注解

查看redis数据,发现authorities字段消失

可以获取正常解析redis数据到loginUser

 可以输出结果

我推测是Spring Security会判断authorities字段是否存在如果getAuthorities方法返回值为null或者该字段加上@JSONField(serialize = false),则不会存入redis中。如下图

其他情况会存入redis中。如下图

但是我们最后要做的是鉴权的时候,方法的返回值不能是null呀。所以只有给authorities字段加上@JSONField(serialize = false)注解才能解决问题。现在突然醒悟了,那我们还要aaaaa这个字段干什么,直接加上authorities字段再给它配个注解,方法里面都写authorities不就解决问题了?是的,确实是这样,因为Spring Security检查的是authorities字段加上@JSONField(serialize = false)注解才会判断要不要写入redis。这个aaaaa这个字段确实多余。

看到这里,大家可能知道问题的原因了,是因为没有定义authorities字段(不能写错!!!)。

查看效果

redis中的数据

 redis解析正常

postman返回数据正常

思考:LoginUser类中字段只写了三个,而且一个加入注解忽略写入redis,为什么还有这么多其他字段?

看一下LoginUser的方法

像不像方法与字段像对应

这样就清晰了,getAuthorities方法应该也可以对应一个字段authorites,如果返回值不为null那个就会有生成字段。存入redis的时候发现这个生成的authorites字段,因为是生成的,没有配置@JSONField(serialize = false)注解,所以会直接存入redis。取出的时候发现没有这个字段,就会报错,就算有这个字段,也解析不出来(重要的事情在文章场景描述的地方)。

这个提醒了我们什么?要规范命名(手动狗头)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringSecurity中授权时fastjson序列化问题 的相关文章

  • Keytool 应用程序在哪里?

    我需要在android中使用mapview控件 但我似乎不明白如何运行keytool 是用eclipse安装的吗 我好像找不到下载链接 Thanks keytool http docs oracle com javase 7 docs te
  • 具有更高可见性的重写方法是良好的实践吗?

    回答这个问题 如何使用 GUI 使用 PaintComponent 初始化 GUI 然后添加基于鼠标的 GUI https stackoverflow com questions 21336141 how to gui using pain
  • 将 jar 作为 Linux 服务运行 - init.d 脚本在启动应用程序时卡住

    我目前正在致力于在 Linux VM 上实现一个可运行的 jar 作为后台服务 我已经使用了找到的例子here https gist github com shirish4you 5089019作为工作的基础 并将 start 方法修改为
  • 如何在spring mvc中从控制器名称+操作名称获取映射的URL?

    是否有现有的解决方案可以从 Spring MVC3 中的 控制器名称 操作名称 获取映射的 URL 例如 asp net mvc 或 Rails 中的 UrlHelper 我觉得非常有用 thx 也许 你想要这样的东西 in your Co
  • 如果在睡眠线程上调用interrupt()会发生什么?

    我有一个线程 然后run I call sleep 如果我中断这个线程会发生什么 MyThread extends Thread public void run try sleep 1000000 catch InterruptedExce
  • 对话框上的 EditText 不返回任何文本

    我太累了 找不到错误 我没有发现任何错误 但我没有从 editText 收到任何文本 请看下面的代码 活动密码 xml
  • 无法使用maven编译java项目

    我正在尝试在 java 16 0 1 上使用 maven 构建 IntelliJ 项目 但它无法编译我的项目 尽管 IntelliJ 能够成功完成 在此之前 我使用maven编译了一个java 15项目 但我决定将所有内容更新到16 0 1
  • Java:使用 HttpURLConnection 的 HTTP PUT

    如何执行 HTTP PUT 我正在使用的类似乎认为它正在执行 PUT 但端点将其视为我执行了 GET 我做错了什么吗 URL url new URL https HttpURLConnection conn HttpURLConnectio
  • Firestore - RecycleView - 图像持有者

    我不知道如何编写图像的支架 我已经设置了 2 个文本 但我不知道图像的支架应该是什么样子 你能帮我告诉我图像的文字应该是什么样子才能正确显示吗 holder artistImage setImageResource model getArt
  • 如何从 Retrofit2 获取字符串响应?

    我正在做 android 正在寻找一种方法来执行超级基本的 http GET POST 请求 我不断收到错误 java lang IllegalArgumentException Unable to create converter for
  • 如何让spring为JdbcMetadataStore创建相应的schema?

    我想使用此处描述的 jdbc 元数据存储 https docs spring io spring integration docs 5 2 0 BUILD SNAPSHOT reference html jdbc html jdbc met
  • 如何获取 WebElement 的父级[重复]

    这个问题在这里已经有答案了 我试过了 private WebElement getParent final WebElement webElement return webElement findElement By xpath 但我得到
  • 无法加载或查找主类,可以在命令行中使用,但不能在 IDE 中使用[重复]

    这个问题在这里已经有答案了 在将其标记为重复之前 请先听我说完 我正在尝试使用 gradle 导入一个 java 项目 功能齐全 适用于所有其他笔记本电脑 没有问题 我的项目 100 正常运行 适用于所有其他笔记本电脑 当我的笔记本电脑被重
  • 获取给定类文件的目录路径

    我遇到的代码尝试从类本身的 class 文件所在的同一目录中读取一些配置文件 File configFiles new File this getClass getResource getPath listFiles new Filenam
  • Cloudfoundry:如何组合两个运行时

    cloundfoundry 有没有办法结合两个运行时环境 我正在将 NodeJS 应用程序部署到 IBM Bluemix 现在 我还希望能够执行独立的 jar 文件 但应用程序失败 APP 0 bin sh 1 java not found
  • 如何记录来自 Akka (Java) 的所有传入消息

    在 Scala 中 您可以使用 LoggingReceive 包装接收函数 如何通过 Java API 实现相同的目标 def receive LoggingReceive case x do something Scala API 有Lo
  • 为什么java中的for-each循环中需要声明变量

    for 每个循环的通常形式是这样的 for Foo bar bars bar doThings 但如果我想保留 bar 直到循环结束 我可以not使用 foreach 循环 Foo bar null Syntax error on toke
  • Android - 9 补丁

    我正在尝试使用 9 块图片创建一个新的微调器背景 我尝试了很多方法来获得完美的图像 但都失败了 s Here is my 9 patch 当我用Draw 9 patch模拟时 内容看起来不错 但是带有箭头的部分没有显示 或者当它显示时 这部
  • Android AutoCompleteTextView 带芯片

    我不确定我是否使用了正确的词语来描述此 UI 功能 但我已附上我希望在我的应用程序中实现的目标的快照 它由 Go SMS 使用 用户在编辑文本中键入联系人 在用户从完成下拉列表中选择联系人后 该联系人将被插入到编辑文本中 如附图所示 编辑文
  • Android 和 Java 中绘制椭圆的区别

    在Java中由于某种原因Ellipse2D Double使用参数 height width x y 当我创建一个RectF在Android中参数是 left top right bottom 所以我对适应差异有点困惑 如果在 Java 中创

随机推荐

  • 【java语法基础】常量与变量、数据类型,以及数据类型的转换

    常量 就是值永远不被改变的量 声明一个常量 需要用final关键字修饰 具体格式 final 常量类型 常量标识符 常量值 例如 final int PIE 18 注 在定义一个常量标识符时 所有的字符都要大写 如果常量标识符由多个单词组成
  • 用python实现数字图片识别神经网络--实现网络训练功能

    上节我们完成了神经网络基本框架的搭建 当时剩下了最重要的一个接口train 也就是通过读取数据自我学习 进而改进网络识别效率的功能尚未实现 从本节开始 我们着手实现该功能 自我训练过程分两步走 第一步是计算输入训练数据 给出网络的计算结果
  • git查看日志

    目录 引言 git查看该项目提交记录 查看指定条数的记录 显示提交的差异 提交的简略信息 按行显示提交信息 按照指定格式显示记录 指定文件的提交记录 指定字符串或函数的提交记录 示例 引言 有时需要对之前所做的一些修改查看记录 这里是查看g
  • STM32F407ZGT6控制舵机(采用高级定时器8)

    前言 32单片机给舵机供电不足 会出现不稳定的情况 舵机鬼畜 所以要外加电源给舵机供电 利用12v锂电池 通过稳压模块降压到5 5v 提供给舵机 稳压电路的gnd一定要接上32单片机的gnd 不共地虽然能供电但数据线无法传输数据 stm32
  • 以太坊ERC-20协议详解

    区块链学习 https github com xianfeng92 Love Ethereum ERC20是以太坊定义的一个 代币标准 https github com ethereum EIPs blob master EIPS eip
  • 计算机网络综合选择题

    计算机网络综合选择题 TCP IP体系结构中的TCP和IP所提供的服务分别为 A 运输层服务和网络层服务 B 运输层服务和应用层服务 C 链路层服务和网络层服务 D 网络层服务和运输层服务 答案 A 2 对于无序接收的滑动窗口协议 若序号位
  • JAVA中的异常处理机制

    JAVA中的异常处理机制 java异常处理中的关键字 try catch finally throw throws return try 检测代码块 在此代码块中一旦检测到异常就会自动跳转到相应的catch try 检测代码块 catch
  • 21_pre_access 阶段

    文章目录 限制每个客户端的并发连接数 limit conn 指令 示例配置 限制每个客户端的每秒处理请求数 limit req 指令 限制每个客户端的并发连接数 ngx http limit conn module 生效阶段 ngx htt
  • Java实现FTP的上传和下载!

    java实现连接FTP服务器 实现文件的上传和下载 一 FTP服务器 FTP服务器 File Transfer Protocol Server 是在互联网上提供文件存储和访问服务的计算机 它们依照FTP协议提供服务 FTP协议是一种专门用来
  • 一文简单了解RPMB

    不知道大家对于RPMB有所了解吗 最近在看这些存储介质的介绍的时候 在推荐里面看到了这个东西 又因为对安全本身就有所涉及学习 所以这里来看看这个东西 学习的内容都是来自前辈们的blog 会在文末附注 1 Flash是什么 关于存储的种类有很
  • 解决mysql忘记密码无法登陆问题

    当我们忘记mysql密码的时候我们不仅无法访问数据库 也无法修改密码 这是个很头疼的问题 下面是跳过用户验证登陆数据库的小技巧 第一步 打开我们安装mysql的目录 复制 D PhpStudy PHPTutorial MySQL bin 地
  • 同一端口有2个前端应用应该如何配置nginx.conf

    需求 业务系统中有2种完全不同角色 页面没有相同模块拆分成了2个应用A和B 但后端是同一个后端 部署的时候要求A和B在同一端口下 问 如何配置nginx 首先我们将A B前端包放到 opt app jhscf deploy html下 这样
  • 电脑如何打开虚拟化设置?

    当你开启Vmware中的虚拟机时 如果出现以上提示 说明你的虚拟化没有打开 在计算机中 虚拟化 英语 Virtualization 是一种资源管理技术 是将计算机的各种实体资源 如服务器 网络 内存及存储等 予以抽象 转换后呈现出来 打破实
  • R语言-随机前沿分析法--SFA

    3 1介绍 生产函数模型 lnqi x i b vi ui 随机生产前沿函数 qi 产出变量向量 x i 投入变量向量 b 变量参数估计 vi 统计噪声的对称随机误差 ui 无效效应 3 2度量技术效率的方法 SFA 参数 DEA 非参数
  • Fortran 90学习之旅(一)Visual Fortran 6.5 的安装与第一个例子

    转载请标明是引用于 http blog csdn net chenyujing1234 源码 http www rayfile com zh cn files e5f02f0a 8799 11e1 b6a2 0015c55db73d 高尔夫
  • Java 中封装JDBC连接到JDBCUtils工具类的详解

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 前言 在JDBC操作中 获取连接和释放资源是经常使用到的 可以将其封装成到一个工具类JDBCUtils中 JDBCUtils中有两个方法
  • .numpy()、.item()、.cpu()、.clone()、.detach()及.data的使用 && tensor类型的转换

    文章目录 numpy item cpu clone detach 及 data的使用 item cpu numpy clone detach data data和 detach 不同点 Tensor类型的转换 numpy item cpu
  • STM32定时器中断

    目录 一 关于STM32定时器中断 1 定时器分类 2 通用定时器的功能特点 3 定时器中断的触发 4 定时时钟计算方法 二 CubeMX初始化配置 1 芯片选型 我们这里运用的STM32F103C8T6 编辑 2 时钟配置 3 TIM2中
  • 经纬恒润OTA仿真测试解决方案为汽车智能化发展保驾护航

    OTA技术是汽车实现完整网联化 智能化体验的基础 自被引用汽车以来 广受研发人员 市场用户的关注 近来 国家有关部门也陆续出台了相应政策 对汽车企业OTA技术的应用进行了约束和规范 因此 OTA技术在量产车型的应用落地 离不开完整的测试验证
  • SpringSecurity中授权时fastjson序列化问题

    最近在复习Spring Security 复习的鉴权的时候出现问题 26 封装权限信息 哔哩哔哩 bilibili 如果是从B站中看到 直接说问题可能出现的原因 可能是private List