利用mybatis-generator自动生成代码
1、mybatis-generator 概述
MyBatis官方提供了逆向工程 mybatis-generator,可以针对数据库表自动生成MyBatis执行所需要的代码(如Mapper.java、Mapper.xml、POJO)。mybatis-generator 有三种用法:命令行、eclipse插件、maven插件。而maven插件的方式比较通用,本文也将概述maven插件的使用方式。
2、pom.xml中配置plugin
(官方文档:Running MyBatis Generator With Maven)
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<configurationFile>
mybatis-generator/generatorConfig.xml
</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.itfsw</groupId>
<artifactId>mybatis-generator-plugin</artifactId>
<version>1.3.8</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
3、generatorConfig.xml配置文件
(官方文档:MyBatis GeneratorXML Configuration File Reference)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="mysqlgenerator" targetRuntime="MyBatis3">
<property name="autoDelimitKeywords" value="true"/>
<!--可以使用``包括字段名,避免字段名与sql保留字冲突报错-->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- 自动生成toString方法 -->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<!-- 自动生成equals方法和hashcode方法 -->
<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>
<!-- 非官方插件 https://github.com/itfsw/mybatis-generator-plugin -->
<!-- 查询单条数据插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.SelectOneByExamplePlugin"/>
<!-- MySQL分页插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.LimitPlugin"/>
<!-- 查询结果选择性返回插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.SelectSelectivePlugin"/>
<!-- Example Criteria 增强插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.ExampleEnhancedPlugin"/>
<!-- 数据Model属性对应Column获取插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.ModelColumnPlugin"/>
<!-- 逻辑删除插件 需配合数据库有对应的字段-->
<plugin type="com.itfsw.mybatis.generator.plugins.LogicalDeletePlugin">
<!-- 这里配置的是全局逻辑删除列和逻辑删除值,当然在table中配置的值会覆盖该全局配置 -->
<!-- 逻辑删除列类型只能为数字、字符串或者布尔类型 -->
<property name="logicalDeleteColumn" value="deleted"/>
<!-- 逻辑删除-已删除值 -->
<property name="logicalDeleteValue" value="1"/>
<!-- 逻辑删除-未删除值 -->
<property name="logicalUnDeleteValue" value="0"/>
</plugin>
<!-- Example 目标包修改插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.ExampleTargetPlugin">
<!-- 修改Example类生成到目标包下 -->
<property name="targetPackage" value="org.linlinjava.litemall.db.domain.example"/>
</plugin>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库连接信息-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false"
userId="litemall"
password="litemall123456"/>
<javaTypeResolver>
<property name="useJSR310Types" value="true"/>
</javaTypeResolver>
<javaModelGenerator targetPackage="org.linlinjava.litemall.db.domain" targetProject="src/main/java"/>
<sqlMapGenerator targetPackage="org.linlinjava.litemall.db.mapper" targetProject="src/main/resources"/>
<javaClientGenerator type="XMLMAPPER" targetPackage="org.linlinjava.litemall.db.mapper"
targetProject="src/main/java"/>
<!--表名-->
<table tableName="litemall_ad">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>
<table tableName="litemall_address">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>
<table tableName="litemall_admin">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<columnOverride column="role_ids" javaType="java.lang.Integer[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
</table>
<table tableName="litemall_goods">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<columnOverride column="gallery" javaType="java.lang.String[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
</table>
<table tableName="litemall_goods_product">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<columnOverride column="specifications" javaType="java.lang.String[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
</table>
<table tableName="litemall_issue">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>
<table tableName="litemall_order_goods">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<columnOverride column="specifications" javaType="java.lang.String[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
<columnOverride column="comments" javaType="java.lang.Integer[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
</table>
<table tableName="litemall_topic">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<columnOverride column="goods" javaType="java.lang.Integer[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
<table tableName="litemall_coupon">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<columnOverride column="goods_value" javaType="java.lang.Integer[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
</table>
<table tableName="litemall_notice_admin">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>
<table tableName="litemall_aftersale">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<columnOverride column="pictures" javaType="java.lang.String[]"
typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
</table>
</context>
</generatorConfiguration>
参考文档
1160. 拼写单词
- 难度:
简单
- 本题涉及算法:
哈希表记数
- 思路:
哈希表记数
- 类似题型:
题目 1160. 拼写单词
给你一份『词汇表』(字符串数组) words
和一张『字母表』(字符串) chars
。
假如你可以用 chars
中的『字母』(字符)拼写出 words
中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。
注意:每次拼写时,chars
中的每个字母都只能用一次。
返回词汇表 words
中你掌握的所有单词的 长度之和。
示例
示例 1:
输入:words = ["cat","bt","hat","tree"], chars = "atach"
输出:6
解释:
可以形成字符串 "cat" 和 "hat",所以答案是 3 + 3 = 6。
示例 2:
输入:words = ["hello","world","leetcode"], chars = "welldonehoneyr"
输出:10
解释:
可以形成字符串 "hello" 和 "world",所以答案是 5 + 5 = 10。
提示:
1 <= words.length <= 1000
1 <= words[i].length, chars.length <= 100
所有字符串中都仅包含小写英文字母
解题思路
- 统计字母出现次数
- 两个哈希表的键值对逐一进行比较即可
友情提示:
遇到有提示字符串仅包含小写(或者大写)英文字母的题,
都可以试着考虑能不能构造长度为26的每个元素分别代表一个字母的数组,来简化计算
对于这道题,用数组c来保存字母表里每个字母出现的次数
如法炮制,再对词汇表中的每个词汇都做一数组w,比较数组w与数组c的对应位置
- 如果w中的都不大于c,就说明该词可以被拼写出,长度计入结果
- 如果w其中有一个超过了c,则说明不可以被拼写,直接跳至下一个(这里用到了带label的continue语法)
代码
python
class Solution(object):
def countCharacters(self, words, chars):
"""
:type words: List[str]
:type chars: str
:rtype: int
"""
res = 0
for word in words:
# for i in word:
# if word.count(i)<=chars.count(i):
# flag = 1
# continue
# else:
# flag = 0
# break
# if flag == 1:
# res += len(word)
if all(word.count(i)<=chars.count(i) for i in word):
res += len(word)
return res
java一
public class Solution {
public int countCharacters(String[] words, String chars) {
int[] c = new int[26];
for(char cc:chars.toCharArray()) {
c[(int)cc-'a']+=1;
}
int res = 0;
a: for(String word:words) {
int[] w = new int[26];
for(char ww:word.toCharArray()) {
w[(int)ww-'a']+=1;
}
for(int i=0;i<26;i++) {
if(w[i]>c[i]) {
continue a;
}
}
res += word.length();
}
return res;
}
}
java二
class Solution {
public int countCharacters(String[] words, String chars) {
int[] abc = new int[26];
for (char ch : chars.toCharArray()) {
int index = ch - 'a';
abc[index] += 1;
}
int sumlen = 0;
a:
for (String word : words) {
int[] sub = abc.clone();// 注意这里 需要用拷贝,如果int[] sub = abc 指定的是同一个对象,
int len = 0;
for (char cha : word.toCharArray()) {
int c = cha - 'a';
if (sub[c] == 0) {
len = 0;
continue a;
} else {
len += 1;
sub[c] -= 1;
}
}
sumlen += len;
}
return sumlen;
}
}
shiro源码篇 - shiro的session共享
github
前情回顾
shiro的session创建与session的查询、更新、过期、删除中,shiro对session的操作基本都讲到了,但还缺一个session共享没有讲解;session共享的原理其实在自定义session管理一文已经讲过了,本文不讲原理,只看看shiro的session共享的实现。
为何需要session共享
如果是单机应用,那么谈不上session共享,session放哪都无所谓,不在乎放到默认的servlet容器中,还是抽出来放到单独的地方;
也就是说session共享是针对集群(或分布式、或分布式集群)的;如果不做session共享,仍然采用默认的方式(session存放到默认的servlet容器),当我们的应用是以集群的方式发布的时候,同个用户的请求会被分发到不同的集群节点(分发依赖具体的负载均衡规则),那么每个处理同个用户请求的节点都会重新生成该用户的session,这些session之间是毫无关联的。那么同个用户的请求会被当成多个不同用户的请求,这肯定是不行的。
如何实现session共享
实现方式其实有很多,甚至可以不做session共享,具体有哪些,大家自行去查资料。本文提供一种方式:redis实现session共享,就是将session从servlet容器抽出来,放到redis中存储,所有集群节点都从redis中对session进行操作。
SessionDAO
SessionDAO其实是用于session持久化的,但里面有缓存部分,具体细节我们往下看
shiro已有SessionDAO的实现如下
SessionDAO接口提供的方法如下
package org.apache.shiro.session.mgt.eis;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import java.io.Serializable;
import java.util.Collection;
/**
* 从EIS操作session的规范(EIS:例如关系型数据库, 文件系统, 持久化缓存等等, 具体依赖DAO实现)
* 提供了典型的CRUD的方法:create, readSession, update, delete
*/
public interface SessionDAO {
/**
* 插入一个新的sesion记录到EIS
*/
Serializable create(Session session);
/**
* 根据会话ID获取会话
*/
Session readSession(Serializable sessionId) throws UnknownSessionException;
/**
* 更新session; 如更新session最后访问时间/停止会话/设置超时时间/设置移除属性等会调用
*/
void update(Session session) throws UnknownSessionException;
/**
* 删除session; 当会话过期/会话停止(如用户退出时)会调用
*/
void delete(Session session);
/**
* 获取当前所有活跃session, 所有状态不是stopped/expired的session
* 如果用户量多此方法影响性能
*/
Collection<Session> getActiveSessions();
}
SessionDAO给出了从持久层(一般而言是关系型数据库)操作session的标准。
AbstractSessionDAO提供了SessionDAO的基本实现,如下
package org.apache.shiro.session.mgt.eis;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import java.io.Serializable;
/**
* SessionDAO的抽象实现, 在会话创建和读取时做一些健全性检查,并在需要时允许可插入的会话ID生成策略.
* SessionDAO的update和delete则留给子类来实现
* EIS需要子类自己实现
*/
public abstract class AbstractSessionDAO implements SessionDAO {
/**
* sessionId生成器
*/
private SessionIdGenerator sessionIdGenerator;
public AbstractSessionDAO() {
this.sessionIdGenerator = new JavaUuidSessionIdGenerator(); // 指定JavaUuidSessionIdGenerator为默认sessionId生成器
}
/**
* 获取sessionId生成器
*/
public SessionIdGenerator getSessionIdGenerator() {
return sessionIdGenerator;
}
/**
* 设置sessionId生成器
*/
public void setSessionIdGenerator(SessionIdGenerator sessionIdGenerator) {
this.sessionIdGenerator = sessionIdGenerator;
}
/**
* 生成一个新的sessionId, 并将它应用到session实例
*/
protected Serializable generateSessionId(Session session) {
if (this.sessionIdGenerator == null) {
String msg = "sessionIdGenerator attribute has not been configured.";
throw new IllegalStateException(msg);
}
return this.sessionIdGenerator.generateId(session);
}
/**
* SessionDAO中create实现; 将创建的sesion保存到EIS.
* 子类doCreate方法的代理,具体的细节委托给了子类的doCreate方法
*/
public Serializable create(Session session) {
Serializable sessionId = doCreate(session);
verifySessionId(sessionId);
return sessionId;
}
/**
* 保证从doCreate返回的sessionId不是null,并且不是已经存在的.
* 目前只实现了null校验,是否已存在是没有校验的,可能shiro的开发者会在后续补上吧.
*/
private void verifySessionId(Serializable sessionId) {
if (sessionId == null) {
String msg = "sessionId returned from doCreate implementation is null. Please verify the implementation.";
throw new IllegalStateException(msg);
}
}
/**
* 分配sessionId给session实例
*/
protected void assignSessionId(Session session, Serializable sessionId) {
((SimpleSession) session).setId(sessionId);
}
/**
* 子类通过实现此方法来持久化Session实例到EIS.
*/
protected abstract Serializable doCreate(Session session);
/**
* SessionDAO中readSession实现; 通过sessionId从EIS获取session对象.
* 子类doReadSession方法的代理,具体的获取细节委托给了子类的doReadSession方法.
*/
public Session readSession(Serializable sessionId) throws UnknownSessionException {
Session s = doReadSession(sessionId);
if (s == null) {
throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
}
return s;
}
/**
* 子类通过实现此方法从EIS获取session实例
*/
protected abstract Session doReadSession(Serializable sessionId);
}
SessionDao的基本实现,实现了SessionDao的create、readSession(具体还是依赖AbstractSessionDAO子类的doCreate、doReadSession实现);同时加入了自己的sessionId生成器,负责sessionId的操作。
CachingSessionDAO提供了session缓存的功能,如下
package org.apache.shiro.session.mgt.eis;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.CacheManagerAware;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.ValidatingSession;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
/**
* 应用层与持久层(EIS,如关系型数据库、文件系统、NOSQL)之间的缓存层实现
* 缓存着所有激活状态的session
* 实现了CacheManagerAware,会在shiro加载的过程中调用此对象的setCacheManager方法
*/
public abstract class CachingSessionDAO extends AbstractSessionDAO implements CacheManagerAware {
/**
* 激活状态的sesion的默认缓存名
*/
public static final String ACTIVE_SESSION_CACHE_NAME = "shiro-activeSessionCache";
/**
* 缓存管理器,用来获取session缓存
*/
private CacheManager cacheManager;
/**
* 用来缓存session的缓存实例
*/
private Cache<Serializable, Session> activeSessions;
/**
* session缓存名, 默认是ACTIVE_SESSION_CACHE_NAME.
*/
private String activeSessionsCacheName = ACTIVE_SESSION_CACHE_NAME;
public CachingSessionDAO() {
}
/**
* 设置缓存管理器
*/
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
/**
* 获取缓存管理器
*/
public CacheManager getCacheManager() {
return cacheManager;
}
/**
* 获取缓存实例的名称,也就是获取activeSessionsCacheName的值
*/
public String getActiveSessionsCacheName() {
return activeSessionsCacheName;
}
/**
* 设置缓存实例的名称,也就是设置activeSessionsCacheName的值
*/
public void setActiveSessionsCacheName(String activeSessionsCacheName) {
this.activeSessionsCacheName = activeSessionsCacheName;
}
/**
* 获取缓存实例
*/
public Cache<Serializable, Session> getActiveSessionsCache() {
return this.activeSessions;
}
/**
* 设置缓存实例
*/
public void setActiveSessionsCache(Cache<Serializable, Session> cache) {
this.activeSessions = cache;
}
/**
* 获取缓存实例
* 注意:不会返回non-null值
*
* @return the active sessions cache instance.
*/
private Cache<Serializable, Session> getActiveSessionsCacheLazy() {
if (this.activeSessions == null) {
this.activeSessions = createActiveSessionsCache();
}
return activeSessions;
}
/**
* 创建缓存实例
*/
protected Cache<Serializable, Session> createActiveSessionsCache() {
Cache<Serializable, Session> cache = null;
CacheManager mgr = getCacheManager();
if (mgr != null) {
String name = getActiveSessionsCacheName();
cache = mgr.getCache(name);
}
return cache;
}
/**
* AbstractSessionDAO中create的重写
* 调用父类(AbstractSessionDAO)的create方法, 然后将session缓存起来
* 返回sessionId
*/
public Serializable create(Session session) {
Serializable sessionId = super.create(session); // 调用父类的create方法
cache(session, sessionId); // 以sessionId作为key缓存session
return sessionId;
}
/**
* 从缓存中获取session; 若sessionId为null,则返回null
*/
protected Session getCachedSession(Serializable sessionId) {
Session cached = null;
if (sessionId != null) {
Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
if (cache != null) {
cached = getCachedSession(sessionId, cache);
}
}
return cached;
}
/**
* 从缓存中获取session
*/
protected Session getCachedSession(Serializable sessionId, Cache<Serializable, Session> cache) {
return cache.get(sessionId);
}
/**
* 缓存session,以sessionId作为key
*/
protected void cache(Session session, Serializable sessionId) {
if (session == null || sessionId == null) {
return;
}
Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
if (cache == null) {
return;
}
cache(session, sessionId, cache);
}
protected void cache(Session session, Serializable sessionId, Cache<Serializable, Session> cache) {
cache.put(sessionId, session);
}
/**
* AbstractSessionDAO中readSession的重写
* 先从缓存中获取,若没有则调用父类的readSession方法获取session
*/
public Session readSession(Serializable sessionId) throws UnknownSessionException {
Session s = getCachedSession(sessionId); // 从缓存中获取
if (s == null) {
s = super.readSession(sessionId); // 调用父类readSession方法获取
}
return s;
}
/**
* SessionDAO中update的实现
* 更新session的状态
*/
public void update(Session session) throws UnknownSessionException {
doUpdate(session); // 更新EIS中的session
if (session instanceof ValidatingSession) {
if (((ValidatingSession) session).isValid()) {
cache(session, session.getId()); // 更新缓存中的session
} else {
uncache(session); // 移除缓存中的sesson
}
} else {
cache(session, session.getId());
}
}
/**
* 由子类去实现,持久化session到EIS
*/
protected abstract void doUpdate(Session session);
/**
* SessionDAO中delete的实现
* 删除session
*/
public void delete(Session session) {
uncache(session); // 从缓存中移除
doDelete(session); // 从EIS中删除
}
/**
* 由子类去实现,从EIS中删除session
*/
protected abstract void doDelete(Session session);
/**
* 从缓存中移除指定的session
*/
protected void uncache(Session session) {
if (session == null) {
return;
}
Serializable id = session.getId();
if (id == null) {
return;
}
Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
if (cache != null) {
cache.remove(id);
}
}
/**
* SessionDAO中getActiveSessions的实现
* 获取所有的存活的session
*/
public Collection<Session> getActiveSessions() {
Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
if (cache != null) {
return cache.values();
} else {
return Collections.emptySet();
}
}
}
是应用层与持久化层之间的缓存层,不用频繁请求持久化层以提升效率。重写了AbstractSessionDAO中的create、readSession方法,实现了SessionDAO中的update、delete、getActiveSessions方法,预留doUpdate和doDelele给子类去实现(doXXX方法操作的是持久层)
MemorySessionDAO,SessionDAO的简单内存实现,如下
package org.apache.shiro.session.mgt.eis;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 基于内存的SessionDao的简单实现,所有的session存在ConcurrentMap中
* DefaultSessionManager默认用的MemorySessionDAO
*/
public class MemorySessionDAO extends AbstractSessionDAO {
private static final Logger log = LoggerFactory.getLogger(MemorySessionDAO.class);
private ConcurrentMap<Serializable, Session> sessions; // 存放session的容器
public MemorySessionDAO() {
this.sessions = new ConcurrentHashMap<Serializable, Session>();
}
// AbstractSessionDAO 中doCreate的重写; 将session存入sessions
protected Serializable doCreate(Session session) {
Serializable sessionId = generateSessionId(session); // 生成sessionId
assignSessionId(session, sessionId); // 将sessionId赋值到session
storeSession(sessionId, session); // 存储session到sessions
return sessionId;
}
// 存储session到sessions
protected Session storeSession(Serializable id, Session session) {
if (id == null) {
throw new NullPointerException("id argument cannot be null.");
}
return sessions.putIfAbsent(id, session);
}
// AbstractSessionDAO 中doReadSession的重写; 从sessions中获取session
protected Session doReadSession(Serializable sessionId) {
return sessions.get(sessionId);
}
// SessionDAO中update的实现; 更新sessions中指定的session
public void update(Session session) throws UnknownSessionException {
storeSession(session.getId(), session);
}
// SessionDAO中delete的实现; 从sessions中移除指定的session
public void delete(Session session) {
if (session == null) {
throw new NullPointerException("session argument cannot be null.");
}
Serializable id = session.getId();
if (id != null) {
sessions.remove(id);
}
}
// SessionDAO中SessionDAO中delete的实现的实现; 获取sessions中全部session
public Collection<Session> SessionDAO中delete的实现() {
Collection<Session> values = sessions.values();
if (CollectionUtils.isEmpty(values)) {
return Collections.emptySet();
} else {
return Collections.unmodifiableCollection(values);
}
}
}
将session保存在内存中,存储结构是ConcurrentHashMap;项目中基本不用,即使我们不实现自己的SessionDAO,一般用的也是EnterpriseCacheSessionDAO。
EnterpriseCacheSessionDAO,提供了缓存功能的session维护,如下
package org.apache.shiro.session.mgt.eis;
import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.MapCache;
import org.apache.shiro.session.Session;
import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;
public class EnterpriseCacheSessionDAO extends CachingSessionDAO {
public EnterpriseCacheSessionDAO() {
// 设置默认缓存器,并实例化MapCache作为cache实例
setCacheManager(new AbstractCacheManager() {
@Override
protected Cache<Serializable, Session> createCache(String name) throws CacheException {
return new MapCache<Serializable, Session>(name, new ConcurrentHashMap<Serializable, Session>());
}
});
}
// AbstractSessionDAO中doCreate的重写;
protected Serializable doCreate(Session session) {
Serializable sessionId = generateSessionId(session);
assignSessionId(session, sessionId);
return sessionId;
}
// AbstractSessionDAO中doReadSession的重写
protected Session doReadSession(Serializable sessionId) {
return null; //should never execute because this implementation relies on parent class to access cache, which
//is where all sessions reside - it is the cache implementation that determines if the
//cache is memory only or disk-persistent, etc.
}
// CachingSessionDAO中doUpdate的重写
protected void doUpdate(Session session) {
//does nothing - parent class persists to cache.
}
// CachingSessionDAO中doDelete的重写
protected void doDelete(Session session) {
//does nothing - parent class removes from cache.
}
}
设置了默认的缓存管理器(AbstractCacheManager)和默认的缓存实例(MapCache),实现了缓存效果。从父类继承的持久化操作方法(doXXX)都是空实现,也就说EnterpriseCacheSessionDAO是没有实现持久化操作的,仅仅只是简单的提供了缓存实现。当然我们可以继承EnterpriseCacheSessionDAO,重写doXXX方法来实现持久化操作。
总结下:SessionDAO定义了从持久层操作session的标准;AbstractSessionDAO提供了SessionDAO的基础实现,如生成会话ID等;CachingSessionDAO提供了对开发者透明的session缓存的功能,只需要设置相应的 CacheManager 即可;MemorySessionDAO直接在内存中进行session维护;而EnterpriseCacheSessionDAO提供了缓存功能的session维护,默认情况下使用 MapCache 实现,内部使用ConcurrentHashMap保存缓存的会话。因为shiro不知道我们需要将session持久化到哪里(关系型数据库,还是文件系统),所以只提供了MemorySessionDAO持久化到内存(听起来怪怪的,内存中能说成持久层吗)
shiro session共享
共享实现
shiro的session共享其实是比较简单的,重写CacheManager,将其操作指向我们的redis,然后实现我们自己的CachingSessionDAO定制缓存操作和缓存持久化。
自定义CacheManager
ShiroRedisCacheManager
package com.lee.shiro.config;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ShiroRedisCacheManager implements CacheManager {
@Autowired
private Cache shiroRedisCache;
@Override
public <K, V> Cache<K, V> getCache(String s) throws CacheException {
return shiroRedisCache;
}
}
ShiroRedisCache
package com.lee.shiro.config;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class ShiroRedisCache<K,V> implements Cache<K,V>{
@Autowired
private RedisTemplate<K,V> redisTemplate;
@Value("${spring.redis.expireTime}")
private long expireTime;
@Override
public V get(K k) throws CacheException {
return redisTemplate.opsForValue().get(k);
}
@Override
public V put(K k, V v) throws CacheException {
redisTemplate.opsForValue().set(k,v,expireTime, TimeUnit.SECONDS);
return null;
}
@Override
public V remove(K k) throws CacheException {
V v = redisTemplate.opsForValue().get(k);
redisTemplate.opsForValue().getOperations().delete(k);
return v;
}
@Override
public void clear() throws CacheException {
}
@Override
public int size() {
return 0;
}
@Override
public Set<K> keys() {
return null;
}
@Override
public Collection<V> values() {
return null;
}
}
自定义CachingSessionDAO
继承EnterpriseCacheSessionDAO,然后重新设置其CacheManager(替换掉默认的内存缓存器),这样也可以实现我们的自定义CachingSessionDAO,但是这是优选吗;如若我们实现持久化,继承EnterpriseCacheSessionDAO是优选,但如果只是实现session缓存,那么CachingSessionDAO是优选,自定义更灵活。那么我们还是继承CachingSessionDAO来实现我们的自定义CachingSessionDAO
ShiroSessionDAO
package com.lee.shiro.config;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.springframework.stereotype.Component;
import java.io.Serializable;
@Component
public class ShiroSessionDAO extends CachingSessionDAO {
@Override
protected void doUpdate(Session session) {
}
@Override
protected void doDelete(Session session) {
}
@Override
protected Serializable doCreate(Session session) {
// 这里绑定sessionId到session,必须要有
Serializable sessionId = generateSessionId(session);
assignSessionId(session, sessionId);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
return null;
}
}
最后将ShiroSessionDAO实例赋值给SessionManager实例,再讲SessionManager实例赋值给SecurityManager实例即可
具体代码请参考spring-boot-shiro
源码解析
底层还是利用Filter + HttpServletRequestWrapper将对session的操作接入到自己的实现中来,而不走默认的servlet容器,这样对session的操作完全由我们自己掌握。
shiro的session创建中其实讲到了shiro中对session操作的基本流程,这里不再赘述,没看的朋友可以先去看看再回过头来看这篇。本文只讲shiro中,如何将一个请求的session接入到自己的实现中来的;shiro中有很多默认的filter,我会单独开一篇来讲shiro的filter,这篇我们先不纠结这些filter。
OncePerRequestFilter中doFilter方法如下
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
if ( request.getAttribute(alreadyFilteredAttributeName) != null ) { // 当前filter已经执行过了,进行下一个filter
log.trace("Filter '{}' already executed. Proceeding without invoking this filter.", getName());
filterChain.doFilter(request, response);
} else //noinspection deprecation
if (/* added in 1.2: */ !isEnabled(request, response) ||
/* retain backwards compatibility: */ shouldNotFilter(request) ) { // 当前filter未被启用或忽略此filter,则进行下一个filter;shouldNotFilter已经被废弃了
log.debug("Filter '{}' is not enabled for the current request. Proceeding without invoking this filter.",
getName());
filterChain.doFilter(request, response);
} else {
// Do invoke this filter...
log.trace("Filter '{}' not yet executed. Executing now.", getName());
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
try {
// 执行当前filter
doFilterInternal(request, response, filterChain);
} finally {
// 一旦请求完成,我们清除当前filter的"已经过滤"的状态
request.removeAttribute(alreadyFilteredAttributeName);
}
}
}
上图中,我可以看到AbstractShiroFilter的doFilterInternal放中将request封装成了shiro自定义的ShiroHttpServletRequest,将response也封装成了shiro自定义的ShiroHttpServletResponse。既然Filter中将request封装了ShiroHttpServletRequest,那么到我们应用的request就是ShiroHttpServletRequest类型,也就是说我们对session的操作最终都是由shiro完成的,而不是默认的servlet容器。
另外补充一点,shiro的session创建不是懒创建的。servlet容器中的session创建是第一次请求session(第一调用request.getSession())时才创建。shiro的session创建如下图
此时,还没登录,但是subject、session已经创建了,只是subject的认证状态为false,说明还没进行登录认证的。至于session创建过程已经保存到redis的流程需要大家自行去跟,或者阅读我之前的博文
总结
- 当以集群方式对外提供服务的时候,不做session共享也是可以的
可以通过ip_hash的机制将同个ip的请求定向到同一台后端,这样保证用户的请求始终是同一台服务处理,与单机应用基本一致了;但这有很多方面的缺陷(具体就不详说了),不推荐使用。
- servlet容器之间做session同步也是可以实现session共享的
一个servlet容器生成session,其他节点的servlet容器从此servlet容器进行session同步,以达到session信息一致。这个也不推荐,某个时间点会有session不一致的问题,毕竟同步过程受到各方面的影响,不能保证session实时一致。
- session共享实现的原理其实都是一样的,都是filter + HttpServletRequestWrapper,只是实现细节会有所区别;有兴趣的可以看下spring-session的实现细节。
- 如果我们采用的spring集成shiro,其实可以将缓存管理器交由spring管理,相当于由spring统一管理缓存。
- shiro的CacheManager不只是管理session缓存,还管理着身份认证缓存、授权缓存,shiro的缓存都是CacheManager管理。但是身份认证缓存默认是关闭的,个人也不推荐开启。
- shiro的session创建时机是在登录认证之前,而不是第一次调用getSession()时。
shiro的工具类-webUtils
这个类提供的很多方法对于我们的平时开发都很有帮助,并不仅仅是shiro内部的应用。
-
getPathWithinApplication(HttpServletRequest),取得不包含应用路径的路径。
-
normalize(String path)将路径修改之后正常显示,去掉或者是替换比如”/”“/.”“/../”“\”等。
-
issueRedirect(ServletRequest, ServletResponse, String),重定向到指定的url。
-
saveRequest(ServletRequest request),将访问的request保存起来,但是注意仅仅保存了url,method和queryString(这个值在post方式提交时是空,所以如果是post时没用,不要保存,因为没法保存参数)
-
redirectToSavedRequest重定向到以前保存的request的路径,但是注意这个方法只对get方式的有效,post方式无效。如果是get的方法会将参数传过去。他是用一个SavedRequest类封装的,里面有三个属性:
private String method;
private String queryString;
private String requestURI;
举个例子:xxx?a=b
其中queryString记录了a=b,
requestURI表示xxx,
在这个类的getRequestUrl可以发现是将queryString和requestURI组合起来了,源码如下:
public String getRequestUrl() {
StringBuilder requestUrl = new StringBuilder(getRequestURI());
if (getQueryString() != null) {
requestUrl.append("?").append(getQueryString());//将所有的参数都带上,但是只对get方法有效。
}
returnrequestUrl.toString();
}
一句话概念
- 事务使用的地方很少,其使用场景主要包括,1.设计到金融或金钱,2.多表操作 什么时候使用mysql事务
- 当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了 ArrayList和LinkedList的区别(含代码)
- 在做查询时 ArrayList 比LinkedList 好些
- select distinct m.perms distinct用于去重,方法解析
- Set: 去重,独一无二,无序 Java Set集合的详解
- BeanFactoryPostProcessor 实现该接口,可以对 bean 操作 Spring的BeanFactoryPostProcessor和BeanPostProcessor
- Server层中方法间调用需要使用 AopContext.currentProxy()获取代理类 如方法A调用方法BAOP切入同类调用方法-AopContext.currentProxy()
((Service)AopContext.currentProxy()).B()
- WebDataBinder 用于把参数绑定到javaBean ,和 @RequestBody @ReauestPram 类似 最全面阐述WebDataBinder理解Spring的数据绑定
- @InitBinder注解 被此注解的方法可以对 WebDataBinder 初始化 和WebDataBinder 一起使用 SpringMVC学习笔记15—–@InitBinder注解
@InitBinder public void initBinder(WebDataBinder binder) { binder.setDisallowedFields("name"); }
- public int indexOf(int ch): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
String accept = request.getHeader("accept"); if (accept != null && accept.indexOf("application/json") != -1)
- shiro提供的filter-AccessControlFilter 过滤器
- AtomicInteger 保证了并发时候的原子性 原子操作类AtomicInteger详解
- @AfterReturning(pointcut = “logPointCut()”, returning = “jsonResult”)//jsonResult 被注解方法的返回值
- ordinal():用于获取某个枚举对象的位置索引值
- HttpServletRequestWrapper类 类似于filter,可用于对用户输入的敏感字眼进行过滤用一个实例来说明HttpServletRequestWrapper类的使用
- AopContext.currentProxy 原理是创建代理类,当service间调用是需要用到 AOP切入同类调用方法-AopContext.currentProxy()
- 被final 修饰的属性,需要设置默认值,或者在构造方法中赋值,否则会编译错误
public class ExpressAutoConfiguration { private final ExpressProperties properties; public ExpressAutoConfiguration(ExpressProperties properties) { this.properties = properties; } }
- @JsonProperty注解的使用 1.命名别名,序列化和反序列化
- ObjectMapper使用 对象与json字符串、byte数组间转化
- 遍历删除map集合中元素时,必须使用迭代iterator map遍历删除异常:ConcurrentModificationException
- springboot使用hibernate validator校验
- 为什么要设置链表头结点?
- springboot自定义参数解析HandlerMethodArgumentResolver 我们可以通过实现HandlerMethodArgumentResolver接口来实现对自定义的参数进行解析。 比如可以解析自定义的时间格式、自定义解析Map对象等这些spring原本不支持的对象格式
- 设计模式
- 对数组排序 Arrays.sort(a1)
- java.lang.NumberFormatException: For input string: “”
- 在spring boot中使用@WebFilter配置filter(包括排除URL) Spring Boot Filter不过滤指定资源,绕过不需要过滤的资源
MediaType源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.http;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.InvalidMimeTypeException;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.MimeType.SpecificityComparator;
import org.springframework.util.comparator.CompoundComparator;
public class MediaType extends MimeType implements Serializable {
private static final long serialVersionUID = 2069937152339670231L;
public static final MediaType ALL = valueOf("*/*");
public static final String ALL_VALUE = "*/*";
public static final MediaType APPLICATION_ATOM_XML = valueOf("application/atom+xml");
public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml";
public static final MediaType APPLICATION_FORM_URLENCODED = valueOf("application/x-www-form-urlencoded");
public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
public static final MediaType APPLICATION_JSON = valueOf("application/json");
public static final String APPLICATION_JSON_VALUE = "application/json";
public static final MediaType APPLICATION_OCTET_STREAM = valueOf("application/octet-stream");
public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream";
public static final MediaType APPLICATION_XHTML_XML = valueOf("application/xhtml+xml");
public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml";
public static final MediaType APPLICATION_XML = valueOf("application/xml");
public static final String APPLICATION_XML_VALUE = "application/xml";
public static final MediaType IMAGE_GIF = valueOf("image/gif");
public static final String IMAGE_GIF_VALUE = "image/gif";
public static final MediaType IMAGE_JPEG = valueOf("image/jpeg");
public static final String IMAGE_JPEG_VALUE = "image/jpeg";
public static final MediaType IMAGE_PNG = valueOf("image/png");
public static final String IMAGE_PNG_VALUE = "image/png";
public static final MediaType MULTIPART_FORM_DATA = valueOf("multipart/form-data");
public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data";
public static final MediaType TEXT_HTML = valueOf("text/html");
public static final String TEXT_HTML_VALUE = "text/html";
public static final MediaType TEXT_PLAIN = valueOf("text/plain");
public static final String TEXT_PLAIN_VALUE = "text/plain";
public static final MediaType TEXT_XML = valueOf("text/xml");
public static final String TEXT_XML_VALUE = "text/xml";
private static final String PARAM_QUALITY_FACTOR = "q";
public static final Comparator<MediaType> QUALITY_VALUE_COMPARATOR = new Comparator<MediaType>() {
public int compare(MediaType mediaType1, MediaType mediaType2) {
double quality1 = mediaType1.getQualityValue();
double quality2 = mediaType2.getQualityValue();
int qualityComparison = Double.compare(quality2, quality1);
if (qualityComparison != 0) {
return qualityComparison;
} else if (mediaType1.isWildcardType() && !mediaType2.isWildcardType()) {
return 1;
} else if (mediaType2.isWildcardType() && !mediaType1.isWildcardType()) {
return -1;
} else if (!mediaType1.getType().equals(mediaType2.getType())) {
return 0;
} else if (mediaType1.isWildcardSubtype() && !mediaType2.isWildcardSubtype()) {
return 1;
} else if (mediaType2.isWildcardSubtype() && !mediaType1.isWildcardSubtype()) {
return -1;
} else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) {
return 0;
} else {
int paramsSize1 = mediaType1.getParameters().size();
int paramsSize2 = mediaType2.getParameters().size();
return paramsSize2 < paramsSize1 ? -1 : (paramsSize2 == paramsSize1 ? 0 : 1);
}
}
};
public static final Comparator<MediaType> SPECIFICITY_COMPARATOR = new SpecificityComparator<MediaType>() {
protected int compareParameters(MediaType mediaType1, MediaType mediaType2) {
double quality1 = mediaType1.getQualityValue();
double quality2 = mediaType2.getQualityValue();
int qualityComparison = Double.compare(quality2, quality1);
return qualityComparison != 0 ? qualityComparison : super.compareParameters(mediaType1, mediaType2);
}
};
public MediaType(String type) {
super(type);
}
public MediaType(String type, String subtype) {
super(type, subtype, Collections.emptyMap());
}
public MediaType(String type, String subtype, Charset charset) {
super(type, subtype, charset);
}
public MediaType(String type, String subtype, double qualityValue) {
this(type, subtype, Collections.singletonMap("q", Double.toString(qualityValue)));
}
public MediaType(MediaType other, Map<String, String> parameters) {
super(other.getType(), other.getSubtype(), parameters);
}
public MediaType(String type, String subtype, Map<String, String> parameters) {
super(type, subtype, parameters);
}
protected void checkParameters(String attribute, String value) {
super.checkParameters(attribute, value);
if ("q".equals(attribute)) {
value = this.unquote(value);
double d = Double.parseDouble(value);
Assert.isTrue(d >= 0.0D && d <= 1.0D, "Invalid quality value \"" + value + "\": should be between 0.0 and 1.0");
}
}
public double getQualityValue() {
String qualityFactory = this.getParameter("q");
return qualityFactory != null ? Double.parseDouble(this.unquote(qualityFactory)) : 1.0D;
}
public boolean includes(MediaType other) {
return super.includes(other);
}
public boolean isCompatibleWith(MediaType other) {
return super.isCompatibleWith(other);
}
public MediaType copyQualityValue(MediaType mediaType) {
if (!mediaType.getParameters().containsKey("q")) {
return this;
} else {
Map<String, String> params = new LinkedHashMap(this.getParameters());
params.put("q", mediaType.getParameters().get("q"));
return new MediaType(this, params);
}
}
public MediaType removeQualityValue() {
if (!this.getParameters().containsKey("q")) {
return this;
} else {
Map<String, String> params = new LinkedHashMap(this.getParameters());
params.remove("q");
return new MediaType(this, params);
}
}
public static MediaType valueOf(String value) {
return parseMediaType(value);
}
public static MediaType parseMediaType(String mediaType) {
MimeType type;
try {
type = MimeTypeUtils.parseMimeType(mediaType);
} catch (InvalidMimeTypeException var4) {
throw new InvalidMediaTypeException(var4);
}
try {
return new MediaType(type.getType(), type.getSubtype(), type.getParameters());
} catch (IllegalArgumentException var3) {
throw new InvalidMediaTypeException(mediaType, var3.getMessage());
}
}
public static List<MediaType> parseMediaTypes(String mediaTypes) {
if (!StringUtils.hasLength(mediaTypes)) {
return Collections.emptyList();
} else {
String[] tokens = mediaTypes.split(",\\s*");
List<MediaType> result = new ArrayList(tokens.length);
String[] var3 = tokens;
int var4 = tokens.length;
for(int var5 = 0; var5 < var4; ++var5) {
String token = var3[var5];
result.add(parseMediaType(token));
}
return result;
}
}
public static String toString(Collection<MediaType> mediaTypes) {
return MimeTypeUtils.toString(mediaTypes);
}
public static void sortBySpecificity(List<MediaType> mediaTypes) {
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
if (mediaTypes.size() > 1) {
Collections.sort(mediaTypes, SPECIFICITY_COMPARATOR);
}
}
public static void sortByQualityValue(List<MediaType> mediaTypes) {
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
if (mediaTypes.size() > 1) {
Collections.sort(mediaTypes, QUALITY_VALUE_COMPARATOR);
}
}
public static void sortBySpecificityAndQuality(List<MediaType> mediaTypes) {
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
if (mediaTypes.size() > 1) {
Collections.sort(mediaTypes, new CompoundComparator(new Comparator[]{SPECIFICITY_COMPARATOR, QUALITY_VALUE_COMPARATOR}));
}
}
}
HttpStatus源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.http;
public enum HttpStatus {
CONTINUE(100, "Continue"),
SWITCHING_PROTOCOLS(101, "Switching Protocols"),
PROCESSING(102, "Processing"),
CHECKPOINT(103, "Checkpoint"),
OK(200, "OK"),
CREATED(201, "Created"),
ACCEPTED(202, "Accepted"),
NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"),
NO_CONTENT(204, "No Content"),
RESET_CONTENT(205, "Reset Content"),
PARTIAL_CONTENT(206, "Partial Content"),
MULTI_STATUS(207, "Multi-Status"),
ALREADY_REPORTED(208, "Already Reported"),
IM_USED(226, "IM Used"),
MULTIPLE_CHOICES(300, "Multiple Choices"),
MOVED_PERMANENTLY(301, "Moved Permanently"),
FOUND(302, "Found"),
/** @deprecated */
@Deprecated
MOVED_TEMPORARILY(302, "Moved Temporarily"),
SEE_OTHER(303, "See Other"),
NOT_MODIFIED(304, "Not Modified"),
/** @deprecated */
@Deprecated
USE_PROXY(305, "Use Proxy"),
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
PERMANENT_REDIRECT(308, "Permanent Redirect"),
BAD_REQUEST(400, "Bad Request"),
UNAUTHORIZED(401, "Unauthorized"),
PAYMENT_REQUIRED(402, "Payment Required"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
METHOD_NOT_ALLOWED(405, "Method Not Allowed"),
NOT_ACCEPTABLE(406, "Not Acceptable"),
PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required"),
REQUEST_TIMEOUT(408, "Request Timeout"),
CONFLICT(409, "Conflict"),
GONE(410, "Gone"),
LENGTH_REQUIRED(411, "Length Required"),
PRECONDITION_FAILED(412, "Precondition Failed"),
PAYLOAD_TOO_LARGE(413, "Payload Too Large"),
/** @deprecated */
@Deprecated
REQUEST_ENTITY_TOO_LARGE(413, "Request Entity Too Large"),
URI_TOO_LONG(414, "URI Too Long"),
/** @deprecated */
@Deprecated
REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"),
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),
REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested range not satisfiable"),
EXPECTATION_FAILED(417, "Expectation Failed"),
I_AM_A_TEAPOT(418, "I'm a teapot"),
/** @deprecated */
@Deprecated
INSUFFICIENT_SPACE_ON_RESOURCE(419, "Insufficient Space On Resource"),
/** @deprecated */
@Deprecated
METHOD_FAILURE(420, "Method Failure"),
/** @deprecated */
@Deprecated
DESTINATION_LOCKED(421, "Destination Locked"),
UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"),
LOCKED(423, "Locked"),
FAILED_DEPENDENCY(424, "Failed Dependency"),
UPGRADE_REQUIRED(426, "Upgrade Required"),
PRECONDITION_REQUIRED(428, "Precondition Required"),
TOO_MANY_REQUESTS(429, "Too Many Requests"),
REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
NOT_IMPLEMENTED(501, "Not Implemented"),
BAD_GATEWAY(502, "Bad Gateway"),
SERVICE_UNAVAILABLE(503, "Service Unavailable"),
GATEWAY_TIMEOUT(504, "Gateway Timeout"),
HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version not supported"),
VARIANT_ALSO_NEGOTIATES(506, "Variant Also Negotiates"),
INSUFFICIENT_STORAGE(507, "Insufficient Storage"),
LOOP_DETECTED(508, "Loop Detected"),
BANDWIDTH_LIMIT_EXCEEDED(509, "Bandwidth Limit Exceeded"),
NOT_EXTENDED(510, "Not Extended"),
NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required");
private final int value;
private final String reasonPhrase;
private HttpStatus(int value, String reasonPhrase) {
this.value = value;
this.reasonPhrase = reasonPhrase;
}
public int value() {
return this.value;
}
public String getReasonPhrase() {
return this.reasonPhrase;
}
public boolean is1xxInformational() {
return HttpStatus.Series.INFORMATIONAL.equals(this.series());
}
public boolean is2xxSuccessful() {
return HttpStatus.Series.SUCCESSFUL.equals(this.series());
}
public boolean is3xxRedirection() {
return HttpStatus.Series.REDIRECTION.equals(this.series());
}
public boolean is4xxClientError() {
return HttpStatus.Series.CLIENT_ERROR.equals(this.series());
}
public boolean is5xxServerError() {
return HttpStatus.Series.SERVER_ERROR.equals(this.series());
}
public HttpStatus.Series series() {
return HttpStatus.Series.valueOf(this);
}
public String toString() {
return Integer.toString(this.value);
}
public static HttpStatus valueOf(int statusCode) {
HttpStatus[] var1 = values();
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
HttpStatus status = var1[var3];
if (status.value == statusCode) {
return status;
}
}
throw new IllegalArgumentException("No matching constant for [" + statusCode + "]");
}
public static enum Series {
INFORMATIONAL(1),
SUCCESSFUL(2),
REDIRECTION(3),
CLIENT_ERROR(4),
SERVER_ERROR(5);
private final int value;
private Series(int value) {
this.value = value;
}
public int value() {
return this.value;
}
public static HttpStatus.Series valueOf(int status) {
int seriesCode = status / 100;
HttpStatus.Series[] var2 = values();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
HttpStatus.Series series = var2[var4];
if (series.value == seriesCode) {
return series;
}
}
throw new IllegalArgumentException("No matching constant for [" + status + "]");
}
public static HttpStatus.Series valueOf(HttpStatus status) {
return valueOf(status.value);
}
}
}
339 post articles, 43 pages.