在SpringBoot中使用JWT
JWT简介
简介
JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记。也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据。此特性便于可伸缩性, 同时保证应用程序的安全。
在身份验证过程中, 当用户使用其凭据成功登录时, 将返回 JSON Web token, 并且必须在本地保存 (通常在本地存储中)。每当用户要访问受保护的路由或资源 (端点) 时, 用户代理(user agent)必须连同请求一起发送 JWT, 通常在授权标头中使用Bearer schema。后端服务器接收到带有 JWT 的请求时, 首先要做的是验证token。
JWT的格式
JWT就是一个字符串,经过加密处理与校验处理的字符串,形式为:A.B.C
A由JWT头部信息header加密得到
B由JWT用到的身份验证信息json数据加密得到
C由A和B加密得到,是校验部分
怎样使用token?
可以放到HTTP请求的请求头中,通常是Authorization字段。
流程图
JWT 实战
加入Maven jwt 依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
在application.proterties中加入配置
# 加密yan
jwt.secret=A0B1C2D3E4F5G6H7I8J9KALBMCNDOEPFQ0R1S2T3U4V5W6X7Y8Z9
# tocken 过期时间,单位秒
jwt.expire=300
# 需要认证的url,多个URL使用英文逗号,分割
jwt.authorised-urls=/apis/fis/redis/**
JwtHelper工具类
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public class JwtHelper {
private Long EXPIRATION_TIME;
private String SECRET;
private final String TOKEN_PREFIX = "Bearer";
private final String HEADER_STRING = "Authorization";
public JwtHelper(<span class="hljs-built_in"><span class="hljs-built_in">String</span></span> secret, long expire) {
<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.EXPIRATION_TIME = expire;
<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.SECRET = secret;
System.out.println(<span class="hljs-string"><span class="hljs-string">"正在初始化Jwthelper,expire="</span></span>+expire);
}
public JSONObject generateToken(<span class="hljs-built_in"><span class="hljs-built_in">Map</span></span><<span class="hljs-built_in"><span class="hljs-built_in">String</span></span>, <span class="hljs-built_in"><span class="hljs-built_in">Object</span></span>> claims) {
Calendar c = Calendar.getInstance();
c.setTime(<span class="hljs-keyword"><span class="hljs-keyword">new</span></span> <span class="hljs-built_in"><span class="hljs-built_in">Date</span></span>());
c.add(Calendar.SECOND, EXPIRATION_TIME.intValue());
<span class="hljs-built_in"><span class="hljs-built_in">Date</span></span> d = c.getTime();
<span class="hljs-built_in"><span class="hljs-built_in">String</span></span> jwt = Jwts.builder()
.setClaims(claims)
.setExpiration(d)
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
JSONObject json = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> JSONObject();
json.put(<span class="hljs-string"><span class="hljs-string">"token"</span></span>,TOKEN_PREFIX + <span class="hljs-string"><span class="hljs-string">" "</span></span> + jwt);
json.put(<span class="hljs-string"><span class="hljs-string">"token-type"</span></span>, TOKEN_PREFIX);
json.put(<span class="hljs-string"><span class="hljs-string">"expire-time"</span></span>,<span class="hljs-keyword"><span class="hljs-keyword">new</span></span> SimpleDateFormat(<span class="hljs-string"><span class="hljs-string">"yyyy-MM-dd HH:ss:mm"</span></span>).format(d) );
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> json;
}
public <span class="hljs-built_in"><span class="hljs-built_in">Map</span></span><<span class="hljs-built_in"><span class="hljs-built_in">String</span></span>, <span class="hljs-built_in"><span class="hljs-built_in">Object</span></span>> validateTokenAndGetClaims(HttpServletRequest request) {
<span class="hljs-built_in"><span class="hljs-built_in">String</span></span> token = request.getHeader(HEADER_STRING);
System.out.println(<span class="hljs-string"><span class="hljs-string">"token is:"</span></span>+token);
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (token == <span class="hljs-literal"><span class="hljs-literal">null</span></span>) {
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> <span class="hljs-literal"><span class="hljs-literal">null</span></span>;
}
<span class="hljs-built_in"><span class="hljs-built_in">Map</span></span><<span class="hljs-built_in"><span class="hljs-built_in">String</span></span>, <span class="hljs-built_in"><span class="hljs-built_in">Object</span></span>> body = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, <span class="hljs-string"><span class="hljs-string">""</span></span>))
.getBody();
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> body;
}
}
JWT过滤器JwtFilter
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
/**
- JWT过滤器
- @author 李庆海
*/
public class JwtFilter implements Filter {
private JwtHelper jwtHelper;
private List<String> urls = null;
private static final org.springframework.util.PathMatcher pathMatcher = new AntPathMatcher();
public JwtFilter(JwtHelper jwtHelper, String[] authorisedUrls) {
this.jwtHelper = jwtHelper;
urls = Arrays.asList(authorisedUrls);
}
<span class="hljs-meta"><span class="hljs-meta">@Override</span></span>
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">init</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(FilterConfig filterConfig)</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span></span></span><span class="hljs-function"> ServletException </span></span>{
<span class="hljs-comment"><span class="hljs-comment">//SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());</span></span>
}
<span class="hljs-meta"><span class="hljs-meta">@Override</span></span>
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">doFilter</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(ServletRequest request, ServletResponse response, FilterChain chain)</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span></span></span><span class="hljs-function"> IOException, ServletException </span></span>{
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding(<span class="hljs-string"><span class="hljs-string">"UTF-8"</span></span>);
httpResponse.setContentType(<span class="hljs-string"><span class="hljs-string">"application/json; charset=utf-8"</span></span>);
httpResponse.setHeader(<span class="hljs-string"><span class="hljs-string">"Access-Control-Allow-Origin"</span></span>, <span class="hljs-string"><span class="hljs-string">"*"</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (<span class="hljs-string"><span class="hljs-string">"OPTIONS"</span></span>.equals(httpRequest.getMethod())) {
httpResponse.setStatus(HttpStatus.NO_CONTENT.value()); <span class="hljs-comment"><span class="hljs-comment">// HttpStatus.SC_NO_CONTENT = 204</span></span>
httpResponse.setHeader(<span class="hljs-string"><span class="hljs-string">"Access-Control-Allow-Credentials"</span></span>, <span class="hljs-string"><span class="hljs-string">"true"</span></span>);
httpResponse.setHeader(<span class="hljs-string"><span class="hljs-string">"Access-Control-Allow-Headers"</span></span>, <span class="hljs-string"><span class="hljs-string">"Content-Type, x-requested-with, Token"</span></span>);
httpResponse.setHeader(<span class="hljs-string"><span class="hljs-string">"Access-Control-Allow-Methods"</span></span>, <span class="hljs-string"><span class="hljs-string">"OPTIONS,GET,POST,DELETE,PUT"</span></span>);
}
String spath = httpRequest.getServletPath();
<span class="hljs-keyword"><span class="hljs-keyword">try</span></span> {
<span class="hljs-comment"><span class="hljs-comment">// 验证受保护的接口</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">for</span></span> (String url : urls) {
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (pathMatcher.match(url, spath)) {
Object token = jwtHelper.validateTokenAndGetClaims(httpRequest);
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (token != <span class="hljs-keyword"><span class="hljs-keyword">null</span></span>) {
chain.doFilter(request, response);
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span>;
}<span class="hljs-keyword"><span class="hljs-keyword">else</span></span>{
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, <span class="hljs-string"><span class="hljs-string">"未授权或者授权已经过期"</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span>;
}
}<span class="hljs-keyword"><span class="hljs-keyword">else</span></span>{
chain.doFilter(request, response);
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span>;
}
}
} <span class="hljs-keyword"><span class="hljs-keyword">catch</span></span> (Exception e) {
e.printStackTrace();
}
chain.doFilter(request, response);
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span>;
}
<span class="hljs-meta"><span class="hljs-meta">@Override</span></span>
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">destroy</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span></span><span class="hljs-function"> </span></span>{
}
}
配置JWT
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.com.yd.fis.client.jwt.JwtFilter;
import cn.com.yd.fis.client.jwt.JwtHelper;
@Configuration
public class JwtConfig {
<span class="hljs-meta"><span class="hljs-meta">@Value</span></span>(<span class="hljs-string"><span class="hljs-string">"${jwt.secret}"</span></span>)
<span class="hljs-keyword"><span class="hljs-keyword">private</span></span> String secret;
<span class="hljs-meta"><span class="hljs-meta">@Value</span></span>(<span class="hljs-string"><span class="hljs-string">"${jwt.expire}"</span></span>)
<span class="hljs-keyword"><span class="hljs-keyword">private</span></span> <span class="hljs-keyword"><span class="hljs-keyword">long</span></span> expire;
<span class="hljs-meta"><span class="hljs-meta">@Value</span></span>(<span class="hljs-string"><span class="hljs-string">"${jwt.authorised-urls}"</span></span>)
<span class="hljs-keyword"><span class="hljs-keyword">private</span></span> String[] authorisedUrls;
<span class="hljs-meta"><span class="hljs-meta">@Bean</span></span>
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> JwtHelper </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">jwtHelperBean</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span></span><span class="hljs-function"> </span></span>{
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> JwtHelper(secret, expire);
}
<span class="hljs-meta"><span class="hljs-meta">@Bean</span></span>
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> FilterRegistrationBean </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">basicFilterRegistrationBean</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span></span><span class="hljs-function"> </span></span>{
FilterRegistrationBean registrationBean = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> FilterRegistrationBean();
JwtFilter filter = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> JwtFilter(jwtHelperBean(), authorisedUrls);
registrationBean.setFilter(filter);
List<String> urlPatterns = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> ArrayList<String>();
urlPatterns.add(<span class="hljs-string"><span class="hljs-string">"/*"</span></span>);
registrationBean.setUrlPatterns(urlPatterns);
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> registrationBean;
}
}
在Controller中使用JWT
此处仅为说明jwt的用法,在实际应用时可以根据具体的业务需要加入不同的或者更多的参数,一并作为claims进行参数传递。
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import cn.com.yd.fis.client.jwt.JwtHelper;
import cn.com.yd.fis.client.util.JsonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@RestController
@RequestMapping("${api-url}/auth")
public class AuthorizeController {
<span class="hljs-meta"><span class="hljs-meta">@Autowired</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">private</span></span> JwtHelper jwtHelper;
<span class="hljs-meta"><span class="hljs-meta">@PostMapping</span></span>(<span class="hljs-string"><span class="hljs-string">"/login"</span></span>)
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> Object </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">login</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(String loginName,String password)</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span></span></span><span class="hljs-function"> Exception </span></span>{
Map<String, Object> claims = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> HashMap<String, Object>();
claims.put(<span class="hljs-string"><span class="hljs-string">"loginName"</span></span>, loginName);
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (<span class="hljs-string"><span class="hljs-string">"1"</span></span>.equals(password)) {
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> JsonResult.success(jwtHelper.generateToken(claims));
} <span class="hljs-keyword"><span class="hljs-keyword">else</span></span> {
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> JsonResult.fail(<span class="hljs-string"><span class="hljs-string">"登录帐号或者登录密码错误"</span></span>);
}
}
}
辅助工具类JsonResult
import com.alibaba.fastjson.JSONObject;
public class JsonResult {
public static JSONObject success(Object obj) {
JSONObject json = new JSONObject();
json.put("state", true);
json.put("msg", "成功");
if (null != obj) {
json.put("obj", obj);
}
return json;
}
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">static</span></span></span><span class="hljs-function"> JSONObject </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">fail</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(Object obj)</span></span></span><span class="hljs-function"> </span></span>{
JSONObject json = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> JSONObject();
json.put(<span class="hljs-string"><span class="hljs-string">"state"</span></span>, <span class="hljs-keyword"><span class="hljs-keyword">false</span></span>);
json.put(<span class="hljs-string"><span class="hljs-string">"msg"</span></span>, <span class="hljs-string"><span class="hljs-string">"失败"</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (<span class="hljs-keyword"><span class="hljs-keyword">null</span></span> != obj) {
json.put(<span class="hljs-string"><span class="hljs-string">"obj"</span></span>, obj);
}
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> json;
}
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">static</span></span></span><span class="hljs-function"> JSONObject </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">toJSONObject</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">boolean</span></span></span></span><span class="hljs-function"><span class="hljs-params"> state, String msg, Object obj)</span></span></span><span class="hljs-function"> </span></span>{
JSONObject json = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> JSONObject();
json.put(<span class="hljs-string"><span class="hljs-string">"state"</span></span>, state);
json.put(<span class="hljs-string"><span class="hljs-string">"msg"</span></span>, msg);
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (<span class="hljs-keyword"><span class="hljs-keyword">null</span></span> != obj) {
json.put(<span class="hljs-string"><span class="hljs-string">"obj"</span></span>, obj);
}
<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> json;
}
}
在SpringBoot中使用JWT的更多相关文章
- 如何在SpringBoot中集成JWT(JSON Web Token)鉴权
这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...
- SpringBoot系列 - 集成JWT实现接口权限认证
会飞的污熊 2018-01-22 16173 阅读 spring jwt springboot RESTful API认证方式 一般来讲,对于RESTful API都会有认证(Authenticati ...
- 在SpringBoot中使用SpringSecurity
@ 目录 提出一个需求 解决方案: 使用SpringSecurity进行解决 SpringSecurity和SpringBoot结合 1. 首先在pom.xml中引入依赖: 2. 配置用户角色和接口的 ...
- SpringBoot 集成SpringSecurity JWT
目录 1. 简介 1.1 SpringSecurity 1.2 OAuth2 1.3 JWT 2. SpringBoot 集成 SpringSecurity 2.1 导入Spring Security ...
- SpringBoot + SpringSecurity + Mybatis-Plus + JWT + Redis 实现分布式系统认证和授权(刷新Token和Token黑名单)
1. 前提 本文在基于SpringBoot整合SpringSecurity实现JWT的前提中添加刷新Token以及添加Token黑名单.在浏览之前,请查看博客: SpringBoot + Sp ...
- SpringBoot中yaml配置对象
转载请在页首注明作者与出处 一:前言 YAML可以代替传统的xx.properties文件,但是它支持声明map,数组,list,字符串,boolean值,数值,NULL,日期,基本满足开发过程中的所 ...
- 如何在SpringBoot中使用JSP ?但强烈不推荐,果断改Themeleaf吧
做WEB项目,一定都用过JSP这个大牌.Spring MVC里面也可以很方便的将JSP与一个View关联起来,使用还是非常方便的.当你从一个传统的Spring MVC项目转入一个Spring Boot ...
- springboot中swaggerUI的使用
demo地址:demo-swagger-springboot springboot中swaggerUI的使用 1.pom文件中添加swagger依赖 2.从github项目中下载swaggerUI 然 ...
- spring-boot+mybatis开发实战:如何在spring-boot中使用myabtis持久层框架
前言: 本项目基于maven构建,使用mybatis-spring-boot作为spring-boot项目的持久层框架 spring-boot中使用mybatis持久层框架与原spring项目使用方式 ...
随机推荐
- 存储过程--mysql
https://zhuanlan.zhihu.com/p/23423264 存储过程-官方解释: 是sql语句和控制语句的预编译集合.以一个名称存储并作为一个单元处理. 存储过程-直白的说: 把需要的 ...
- chrome浏览器 新打开的页面覆盖当前页面
chrome浏览器 本应该新打开一个页面,却覆盖了当前页面. 解决办法:使用鼠标中键打开一次,后续即可正常使用.
- C位域的初步了解
以为C中的东西了解的差不多了...今天却是第一次才看到位域这个概念, 闲来无事的时候读起了编程之美,看一个问题的时候有种解答用到了位域, 位域的结构体定义,变量声明和结构体很相似: struct (结 ...
- excel怎么制作三维圆环图表
excel怎么制作三维圆环图表 excel怎么制作三维圆环图表?excel中想要制作一个三维圆环图表,该怎么制作呢?下面我们就来看看详细的教程,很简单,在Excel中,可以通过自带的圆环图功能生成二维 ...
- php安装oci8和pdo_oci扩展实现连接oracle数据库
PHP一般跟MySQL数据库搭配使用,但最近遇到一个需求需要实现PHP连接Oracle,了解到PHP可以通过pdo_oci和oci8扩展来连接Oracle,这里将安装的过程记录下来. 安装环境:PHP ...
- 使用 store 来优化 React 组件
在使用 React 编写组件的时候,我们常常会碰到两个不同的组件之间需要共享状态情况,而通常的做法就是提升状态到父组件.但是这样做会有一个问题,就是尽管只有两个组件需要这个状态,但是因为把状态提到了父 ...
- POJ1485 Sumdiv
Sumdiv Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 22680 Accepted: 5660 Descripti ...
- Leetcode3.Longest Substring Without Repeating Characters无重复字符的最长字串
给定一个字符串,找出不含有重复字符的最长子串的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc",其长度为 ...
- 洛谷 P2486 [SDOI2011]染色 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 PushDown与Update Q AC代码 总结与拓展 题面 题目链接 P2486 ...
- 跟我一起认识axure(一)
第一步下载:https://www.axure.com.cn/ 第二步点击安装,一路next 第三步:认识Axure RP工作界面