1. renren-fast后端源码参考-配置和对应工具

1.1. 前言

  1. renren-fast是个开源的前后端分离快速开放平台,没有自己框架的同学可以直接使用它的,而我打算浏览一遍它的代码,提取一些好用的模块和功能结合自己的框架
  2. 这里我会罗列所有值得参考的功能点,可能有点多,那就分几块罗列
  3. 项目地址
  4. 由于renren本身的文档是需要购买才能观看,但实际上源码难度还是蛮低的,可以直接分模块引用需要的代码,参考我一下的模块划分

1.2. 代码

这里的代码提取是为了方便单独模块的集成

1.2.1. Xss

  1. Xss配置
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy; import javax.servlet.DispatcherType; /**
* Filter配置
*/
@Configuration
public class FilterConfig { @Bean
public FilterRegistrationBean shiroFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
//该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
registration.addInitParameter("targetFilterLifecycle", "true");
registration.setEnabled(true);
registration.setOrder(Integer.MAX_VALUE - 1);
registration.addUrlPatterns("/*");
return registration;
} @Bean
public FilterRegistrationBean xssFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
registration.setName("xssFilter");
registration.setOrder(Integer.MAX_VALUE);
return registration;
}
}
/**
* XSS过滤
*/
public class XssFilter implements Filter { @Override
public void init(FilterConfig config) throws ServletException {
} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
(HttpServletRequest) request);
chain.doFilter(xssRequest, response);
} @Override
public void destroy() {
} }
  • XssHttpServletRequestWrapper
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map; /**
* XSS过滤处理
*
* @author Mark sunlightcs@gmail.com
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
//没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
HttpServletRequest orgRequest;
//html过滤
private final static HTMLFilter htmlFilter = new HTMLFilter(); public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
orgRequest = request;
} @Override
public ServletInputStream getInputStream() throws IOException {
//非json类型,直接返回
if(!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))){
return super.getInputStream();
} //为空,直接返回
String json = IOUtils.toString(super.getInputStream(), "utf-8");
if (StringUtils.isBlank(json)) {
return super.getInputStream();
} //xss过滤
json = xssEncode(json);
final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8"));
return new ServletInputStream() {
@Override
public boolean isFinished() {
return true;
} @Override
public boolean isReady() {
return true;
} @Override
public void setReadListener(ReadListener readListener) { } @Override
public int read() throws IOException {
return bis.read();
}
};
} @Override
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (StringUtils.isNotBlank(value)) {
value = xssEncode(value);
}
return value;
} @Override
public String[] getParameterValues(String name) {
String[] parameters = super.getParameterValues(name);
if (parameters == null || parameters.length == 0) {
return null;
} for (int i = 0; i < parameters.length; i++) {
parameters[i] = xssEncode(parameters[i]);
}
return parameters;
} @Override
public Map<String,String[]> getParameterMap() {
Map<String,String[]> map = new LinkedHashMap<>();
Map<String,String[]> parameters = super.getParameterMap();
for (String key : parameters.keySet()) {
String[] values = parameters.get(key);
for (int i = 0; i < values.length; i++) {
values[i] = xssEncode(values[i]);
}
map.put(key, values);
}
return map;
} @Override
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (StringUtils.isNotBlank(value)) {
value = xssEncode(value);
}
return value;
} private String xssEncode(String input) {
return htmlFilter.filter(input);
} /**
* 获取最原始的request
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
} /**
* 获取最原始的request
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
if (request instanceof XssHttpServletRequestWrapper) {
return ((XssHttpServletRequestWrapper) request).getOrgRequest();
} return request;
} }
  • html过滤
public final class HTMLFilter {

    /** regex flag union representing /si modifiers in php **/
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
private static final Pattern P_END_ARROW = Pattern.compile("^>");
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_AMP = Pattern.compile("&");
private static final Pattern P_QUOTE = Pattern.compile("<");
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); // @xxx could grow large... maybe use sesat's ReferenceMap
private static final ConcurrentMap<String,Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
private static final ConcurrentMap<String,Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>(); /** set of allowed html elements, along with allowed attributes for each element **/
private final Map<String, List<String>> vAllowed;
/** counts of open tags for each (allowable) html element **/
private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>(); /** html elements which must always be self-closing (e.g. "<img />") **/
private final String[] vSelfClosingTags;
/** html elements which must always have separate opening and closing tags (e.g. "<b></b>") **/
private final String[] vNeedClosingTags;
/** set of disallowed html elements **/
private final String[] vDisallowed;
/** attributes which should be checked for valid protocols **/
private final String[] vProtocolAtts;
/** allowed protocols **/
private final String[] vAllowedProtocols;
/** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") **/
private final String[] vRemoveBlanks;
/** entities allowed within html markup **/
private final String[] vAllowedEntities;
/** flag determining whether comments are allowed in input String. */
private final boolean stripComment;
private final boolean encodeQuotes;
private boolean vDebug = false;
/**
* flag determining whether to try to make tags when presented with "unbalanced"
* angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false,
* unbalanced angle brackets will be html escaped.
*/
private final boolean alwaysMakeTags; /** Default constructor.
*
*/
public HTMLFilter() {
vAllowed = new HashMap<>(); final ArrayList<String> a_atts = new ArrayList<String>();
a_atts.add("href");
a_atts.add("target");
vAllowed.put("a", a_atts); final ArrayList<String> img_atts = new ArrayList<String>();
img_atts.add("src");
img_atts.add("width");
img_atts.add("height");
img_atts.add("alt");
vAllowed.put("img", img_atts); final ArrayList<String> no_atts = new ArrayList<String>();
vAllowed.put("b", no_atts);
vAllowed.put("strong", no_atts);
vAllowed.put("i", no_atts);
vAllowed.put("em", no_atts); vSelfClosingTags = new String[]{"img"};
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
vDisallowed = new String[]{};
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
vProtocolAtts = new String[]{"src", "href"};
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
stripComment = true;
encodeQuotes = true;
alwaysMakeTags = true;
} /** Set debug flag to true. Otherwise use default settings. See the default constructor.
*
* @param debug turn debug on with a true argument
*/
public HTMLFilter(final boolean debug) {
this();
vDebug = debug; } /** Map-parameter configurable constructor.
*
* @param conf map containing configuration. keys match field names.
*/
public HTMLFilter(final Map<String,Object> conf) { assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
vDisallowed = (String[]) conf.get("vDisallowed");
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
} private void reset() {
vTagCounts.clear();
} private void debug(final String msg) {
if (vDebug) {
Logger.getAnonymousLogger().info(msg);
}
} //---------------------------------------------------------------
// my versions of some PHP library functions
public static String chr(final int decimal) {
return String.valueOf((char) decimal);
} public static String htmlSpecialChars(final String s) {
String result = s;
result = regexReplace(P_AMP, "&amp;", result);
result = regexReplace(P_QUOTE, "&quot;", result);
result = regexReplace(P_LEFT_ARROW, "&lt;", result);
result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
return result;
} //---------------------------------------------------------------
/**
* given a user submitted input String, filter out any invalid or restricted
* html.
*
* @param input text (i.e. submitted by a user) than may contain html
* @return "clean" version of input, with only valid, whitelisted html elements allowed
*/
public String filter(final String input) {
reset();
String s = input; debug("************************************************");
debug(" INPUT: " + input); s = escapeComments(s);
debug(" escapeComments: " + s); s = balanceHTML(s);
debug(" balanceHTML: " + s); s = checkTags(s);
debug(" checkTags: " + s); s = processRemoveBlanks(s);
debug("processRemoveBlanks: " + s); s = validateEntities(s);
debug(" validateEntites: " + s); debug("************************************************\n\n");
return s;
} public boolean isAlwaysMakeTags(){
return alwaysMakeTags;
} public boolean isStripComments(){
return stripComment;
} private String escapeComments(final String s) {
final Matcher m = P_COMMENTS.matcher(s);
final StringBuffer buf = new StringBuffer();
if (m.find()) {
final String match = m.group(1); //(.*?)
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
}
m.appendTail(buf); return buf.toString();
} private String balanceHTML(String s) {
if (alwaysMakeTags) {
//
// try and form html
//
s = regexReplace(P_END_ARROW, "", s);
s = regexReplace(P_BODY_TO_END, "<$1>", s);
s = regexReplace(P_XML_CONTENT, "$1<$2", s); } else {
//
// escape stray brackets
//
s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s); //
// the last regexp causes '<>' entities to appear
// (we need to do a lookahead assertion so that the last bracket can
// be used in the next pass of the regexp)
//
s = regexReplace(P_BOTH_ARROWS, "", s);
} return s;
} private String checkTags(String s) {
Matcher m = P_TAGS.matcher(s); final StringBuffer buf = new StringBuffer();
while (m.find()) {
String replaceStr = m.group(1);
replaceStr = processTag(replaceStr);
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
}
m.appendTail(buf); s = buf.toString(); // these get tallied in processTag
// (remember to reset before subsequent calls to filter method)
for (String key : vTagCounts.keySet()) {
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
s += "</" + key + ">";
}
} return s;
} private String processRemoveBlanks(final String s) {
String result = s;
for (String tag : vRemoveBlanks) {
if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
}
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
}
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
} return result;
} private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
Matcher m = regex_pattern.matcher(s);
return m.replaceAll(replacement);
} private String processTag(final String s) {
// ending tags
Matcher m = P_END_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
if (allowed(name)) {
if (!inArray(name, vSelfClosingTags)) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) - 1);
return "</" + name + ">";
}
}
}
} // starting tags
m = P_START_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
final String body = m.group(2);
String ending = m.group(3); //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
if (allowed(name)) {
String params = ""; final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
final List<String> paramNames = new ArrayList<String>();
final List<String> paramValues = new ArrayList<String>();
while (m2.find()) {
paramNames.add(m2.group(1)); //([a-z0-9]+)
paramValues.add(m2.group(3)); //(.*?)
}
while (m3.find()) {
paramNames.add(m3.group(1)); //([a-z0-9]+)
paramValues.add(m3.group(3)); //([^\"\\s']+)
} String paramName, paramValue;
for (int ii = 0; ii < paramNames.size(); ii++) {
paramName = paramNames.get(ii).toLowerCase();
paramValue = paramValues.get(ii); // debug( "paramName='" + paramName + "'" );
// debug( "paramValue='" + paramValue + "'" );
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); if (allowedAttribute(name, paramName)) {
if (inArray(paramName, vProtocolAtts)) {
paramValue = processParamProtocol(paramValue);
}
params += " " + paramName + "=\"" + paramValue + "\"";
}
} if (inArray(name, vSelfClosingTags)) {
ending = " /";
} if (inArray(name, vNeedClosingTags)) {
ending = "";
} if (ending == null || ending.length() < 1) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) + 1);
} else {
vTagCounts.put(name, 1);
}
} else {
ending = " /";
}
return "<" + name + params + ending + ">";
} else {
return "";
}
} // comments
m = P_COMMENT.matcher(s);
if (!stripComment && m.find()) {
return "<" + m.group() + ">";
} return "";
} private String processParamProtocol(String s) {
s = decodeEntities(s);
final Matcher m = P_PROTOCOL.matcher(s);
if (m.find()) {
final String protocol = m.group(1);
if (!inArray(protocol, vAllowedProtocols)) {
// bad protocol, turn into local anchor link instead
s = "#" + s.substring(protocol.length() + 1, s.length());
if (s.startsWith("#//")) {
s = "#" + s.substring(3, s.length());
}
}
} return s;
} private String decodeEntities(String s) {
StringBuffer buf = new StringBuffer(); Matcher m = P_ENTITY.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.decode(match).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString(); buf = new StringBuffer();
m = P_ENTITY_UNICODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString(); buf = new StringBuffer();
m = P_ENCODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString(); s = validateEntities(s);
return s;
} private String validateEntities(final String s) {
StringBuffer buf = new StringBuffer(); // validate entities throughout the string
Matcher m = P_VALID_ENTITIES.matcher(s);
while (m.find()) {
final String one = m.group(1); //([^&;]*)
final String two = m.group(2); //(?=(;|&|$))
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
}
m.appendTail(buf); return encodeQuotes(buf.toString());
} private String encodeQuotes(final String s){
if(encodeQuotes){
StringBuffer buf = new StringBuffer();
Matcher m = P_VALID_QUOTES.matcher(s);
while (m.find()) {
final String one = m.group(1); //(>|^)
final String two = m.group(2); //([^<]+?)
final String three = m.group(3); //(<|$)
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
}
m.appendTail(buf);
return buf.toString();
}else{
return s;
}
} private String checkEntity(final String preamble, final String term) { return ";".equals(term) && isValidEntity(preamble)
? '&' + preamble
: "&amp;" + preamble;
} private boolean isValidEntity(final String entity) {
return inArray(entity, vAllowedEntities);
} private static boolean inArray(final String s, final String[] array) {
for (String item : array) {
if (item != null && item.equals(s)) {
return true;
}
}
return false;
} private boolean allowed(final String name) {
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
} private boolean allowedAttribute(final String name, final String paramName) {
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
}
}

1.2.2. shiro

shiro需要引入pom

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>

shiro配置

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; /**
* Shiro配置
* */
@Configuration
public class ShiroConfig { @Bean("securityManager")
public SecurityManager securityManager(OAuth2Realm oAuth2Realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth2Realm);
securityManager.setRememberMeManager(null);
return securityManager;
} @Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager); //oauth过滤
Map<String, Filter> filters = new HashMap<>();
filters.put("oauth2", new OAuth2Filter());
shiroFilter.setFilters(filters); Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/webjars/**", "anon");
filterMap.put("/druid/**", "anon");
filterMap.put("/app/**", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/v2/api-docs", "anon");
filterMap.put("/swagger-ui.html", "anon");
filterMap.put("/swagger-resources/**", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/aaa.txt", "anon");
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter;
} @Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} @Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
} }
import com.google.gson.Gson;
import io.renren.common.utils.HttpContextUtils;
import io.renren.common.utils.R;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; /**
* oauth2过滤器
* */
public class OAuth2Filter extends AuthenticatingFilter { @Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
//获取请求token
String token = getRequestToken((HttpServletRequest) request); if(StringUtils.isBlank(token)){
return null;
} return new OAuth2Token(token);
} @Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){
return true;
} return false;
} @Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
//获取请求token,如果token不存在,直接返回401
String token = getRequestToken((HttpServletRequest) request);
if(StringUtils.isBlank(token)){
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token")); httpResponse.getWriter().print(json); return false;
} return executeLogin(request, response);
} @Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json;charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
try {
//处理登录失败的异常
Throwable throwable = e.getCause() == null ? e : e.getCause();
R r = R.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage()); String json = new Gson().toJson(r);
httpResponse.getWriter().print(json);
} catch (IOException e1) { } return false;
} /**
* 获取请求的token
*/
private String getRequestToken(HttpServletRequest httpRequest){
//从header中获取token
String token = httpRequest.getHeader("token"); //如果header中不存在token,则从参数中获取token
if(StringUtils.isBlank(token)){
token = httpRequest.getParameter("token");
} return token;
} }
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import java.util.Set; /**
* 认证
*
*/
@Component
public class OAuth2Realm extends AuthorizingRealm {
@Autowired
private ShiroService shiroService; @Override
public boolean supports(AuthenticationToken token) {
return token instanceof OAuth2Token;
} /**
* 授权(验证权限时调用)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal();
Long userId = user.getUserId(); //用户权限列表
Set<String> permsSet = shiroService.getUserPermissions(userId); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
} /**
* 认证(登录时调用)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String accessToken = (String) token.getPrincipal(); //根据accessToken,查询用户信息
SysUserTokenEntity tokenEntity = shiroService.queryByToken(accessToken);
//token失效
if(tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()){
throw new IncorrectCredentialsException("token失效,请重新登录");
} //查询用户信息
SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId());
//账号锁定
if(user.getStatus() == 0){
throw new LockedAccountException("账号已被锁定,请联系管理员");
} SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
return info;
}
}

对应的用户设计

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.renren.common.validator.group.AddGroup;
import io.renren.common.validator.group.UpdateGroup;
import lombok.Data; import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.util.Date;
import java.util.List; /**
* 系统用户
* */
@Data
@TableName("sys_user")
public class SysUserEntity implements Serializable {
private static final long serialVersionUID = 1L; /**
* 用户ID
*/
@TableId
private Long userId; /**
* 用户名
*/
@NotBlank(message="用户名不能为空", groups = {AddGroup.class, UpdateGroup.class})
private String username; /**
* 密码
*/
@NotBlank(message="密码不能为空", groups = AddGroup.class)
private String password; /**
* 盐
*/
private String salt; /**
* 邮箱
*/
@NotBlank(message="邮箱不能为空", groups = {AddGroup.class, UpdateGroup.class})
@Email(message="邮箱格式不正确", groups = {AddGroup.class, UpdateGroup.class})
private String email; /**
* 手机号
*/
private String mobile; /**
* 状态 0:禁用 1:正常
*/
private Integer status; /**
* 角色ID列表
*/
@TableField(exist=false)
private List<Long> roleIdList; /**
* 创建者ID
*/
private Long createUserId; /**
* 创建时间
*/
private Date createTime; }
/**
* 系统用户Token
* */
@Data
@TableName("sys_user_token")
public class SysUserTokenEntity implements Serializable {
private static final long serialVersionUID = 1L; //用户ID
@TableId(type = IdType.INPUT)
private Long userId;
//token
private String token;
//过期时间
private Date expireTime;
//更新时间
private Date updateTime; }
/**
* shiro相关接口
* */
public interface ShiroService {
/**
* 获取用户权限列表
*/
Set<String> getUserPermissions(long userId); SysUserTokenEntity queryByToken(String token); /**
* 根据用户ID,查询用户
* @param userId
*/
SysUserEntity queryUser(Long userId);
}

shiro工具类

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject; /**
* Shiro工具类
* */
public class ShiroUtils { public static Session getSession() {
return SecurityUtils.getSubject().getSession();
} public static Subject getSubject() {
return SecurityUtils.getSubject();
} public static SysUserEntity getUserEntity() {
return (SysUserEntity)SecurityUtils.getSubject().getPrincipal();
} public static Long getUserId() {
return getUserEntity().getUserId();
} public static void setSessionAttribute(Object key, Object value) {
getSession().setAttribute(key, value);
} public static Object getSessionAttribute(Object key) {
return getSession().getAttribute(key);
} public static boolean isLogin() {
return SecurityUtils.getSubject().getPrincipal() != null;
} public static String getKaptcha(String key) {
Object kaptcha = getSessionAttribute(key);
if(kaptcha == null){
throw new RRException("验证码已失效");
}
getSession().removeAttribute(key);
return kaptcha.toString();
} }
/**
* 自定义异常
*
*/
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L; private String msg;
private int code = 500; public RRException(String msg) {
super(msg);
this.msg = msg;
} public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
} public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
} public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} }

1.2.3. cors跨域

@Configuration
public class CorsConfig implements WebMvcConfigurer { @Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}

1.2.4. 验证码

  1. 使用了Kaptcha
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>0.0.9</version>
</dependency>
  1. 配置
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.Properties; /**
* 生成验证码配置
* */
@Configuration
public class KaptchaConfig { @Bean
public DefaultKaptcha producer() {
Properties properties = new Properties();
properties.put("kaptcha.border", "no");
properties.put("kaptcha.textproducer.font.color", "black");
properties.put("kaptcha.textproducer.char.space", "5");
properties.put("kaptcha.textproducer.font.names", "Arial,Courier,cmr10,宋体,楷体,微软雅黑");
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
  1. controller层
	/**
* 验证码
*/
@GetMapping("captcha.jpg")
public void captcha(HttpServletResponse response, String uuid)throws IOException {
response.setHeader("Cache-Control", "no-store, no-cache");
response.setContentType("image/jpeg"); //获取图片验证码
BufferedImage image = sysCaptchaService.getCaptcha(uuid); ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "jpg", out);
IOUtils.closeQuietly(out);
}
//生成文字验证码
String code = producer.createText();
//生成图片
BufferedImage image = producer.createImage(code);

1.2.5. mybatis-plus配置

  1. pom引入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.7.1</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.0.7.1</version>
</dependency>
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* mybatis-plus配置
*
*/
@Configuration
public class MybatisPlusConfig { /**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
} @Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}

1.2.6. redis配置

import org.springframework.beans.factory.annotation.Autowired;
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.*;
import org.springframework.data.redis.serializer.StringRedisSerializer; /**
* Redis配置
*/
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory; @Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
} @Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
} @Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
} @Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
} @Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
} @Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
  • 对应的工具类
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; /**
* Redis工具类
* */
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ValueOperations<String, String> valueOperations;
@Autowired
private HashOperations<String, String, Object> hashOperations;
@Autowired
private ListOperations<String, Object> listOperations;
@Autowired
private SetOperations<String, Object> setOperations;
@Autowired
private ZSetOperations<String, Object> zSetOperations;
/** 默认过期时长,单位:秒 */
public final static long DEFAULT_EXPIRE = 60 * 60 * 24;
/** 不设置过期时长 */
public final static long NOT_EXPIRE = -1;
private final static Gson gson = new Gson(); public void set(String key, Object value, long expire){
valueOperations.set(key, toJson(value));
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
} public void set(String key, Object value){
set(key, value, DEFAULT_EXPIRE);
} public <T> T get(String key, Class<T> clazz, long expire) {
String value = valueOperations.get(key);
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
return value == null ? null : fromJson(value, clazz);
} public <T> T get(String key, Class<T> clazz) {
return get(key, clazz, NOT_EXPIRE);
} public String get(String key, long expire) {
String value = valueOperations.get(key);
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
return value;
} public String get(String key) {
return get(key, NOT_EXPIRE);
} public void delete(String key) {
redisTemplate.delete(key);
} /**
* Object转成JSON数据
*/
private String toJson(Object object){
if(object instanceof Integer || object instanceof Long || object instanceof Float ||
object instanceof Double || object instanceof Boolean || object instanceof String){
return String.valueOf(object);
}
return gson.toJson(object);
} /**
* JSON数据,转成Object
*/
private <T> T fromJson(String json, Class<T> clazz){
return gson.fromJson(json, clazz);
}
}

其中gson对象是来自qiniu-java-sdk,不需要的可以剔除或者一般国内就用fastjson

  • 切面,用来开启关闭redis缓存
/**
* Redis切面处理类
*
*/
@Aspect
@Configuration
public class RedisAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
//是否开启redis缓存 true开启 false关闭
@Value("${spring.redis.open: false}")
private boolean open; @Around("execution(* io.renren.common.utils.RedisUtils.*(..))")
public Object around(ProceedingJoinPoint point) throws Throwable {
Object result = null;
if(open){
try{
result = point.proceed();
}catch (Exception e){
logger.error("redis error", e);
throw new RRException("Redis服务异常");
}
}
return result;
}
}

1.2.7. Swagger配置

  1. pom
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
  1. 配置
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.List; import static com.google.common.collect.Lists.newArrayList; @Configuration
@EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer { @Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//加了ApiOperation注解的类,才生成接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//包下的类,才生成接口文档
//.apis(RequestHandlerSelectors.basePackage("io.renren.controller"))
.paths(PathSelectors.any())
.build()
.securitySchemes(security());
} private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("人人开源")
.description("renren-fast文档")
.termsOfServiceUrl("https://www.renren.io")
.version("3.0.0")
.build();
} private List<ApiKey> security() {
return newArrayList(
new ApiKey("token", "token", "header")
);
} }

1.2.8. 日志

  • 通过注解记录日志
import com.google.gson.Gson;
import io.renren.common.annotation.SysLog;
import io.renren.common.utils.HttpContextUtils;
import io.renren.common.utils.IPUtils;
import io.renren.modules.sys.entity.SysLogEntity;
import io.renren.modules.sys.entity.SysUserEntity;
import io.renren.modules.sys.service.SysLogService;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date; /**
* 系统日志,切面处理类
*/
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService; @Pointcut("@annotation(io.renren.common.annotation.SysLog)")
public void logPointCut() { } @Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime; //保存日志
saveSysLog(point, time); return result;
} private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); SysLogEntity sysLog = new SysLogEntity();
SysLog syslog = method.getAnnotation(SysLog.class);
if(syslog != null){
//注解上的描述
sysLog.setOperation(syslog.value());
} //请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()"); //请求的参数
Object[] args = joinPoint.getArgs();
try{
String params = new Gson().toJson(args);
sysLog.setParams(params);
}catch (Exception e){ } //获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request)); //用户名
String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername();
sysLog.setUsername(username); sysLog.setTime(time);
sysLog.setCreateDate(new Date());
//保存系统日志
sysLogService.save(sysLog);
}
}
  • 日志对应的bean
/**
* 系统日志
*
*/
@Data
@TableName("sys_log")
public class SysLogEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId
private Long id;
//用户名
private String username;
//用户操作
private String operation;
//请求方法
private String method;
//请求参数
private String params;
//执行时长(毫秒)
private Long time;
//IP地址
private String ip;
//创建时间
private Date createDate; }
  • 注解
/**
* 系统日志注解
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog { String value() default "";
}

1.2.9. 校验工具

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set; /**
* hibernate-validator校验工具类
*
* 参考文档:http://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/
*/
public class ValidatorUtils {
private static Validator validator; static {
validator = Validation.buildDefaultValidatorFactory().getValidator();
} /**
* 校验对象
* @param object 待校验对象
* @param groups 待校验的组
* @throws RRException 校验不通过,则报RRException异常
*/
public static void validateEntity(Object object, Class<?>... groups)
throws RRException {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
StringBuilder msg = new StringBuilder();
for(ConstraintViolation<Object> constraint: constraintViolations){
msg.append(constraint.getMessage()).append("<br>");
}
throw new RRException(msg.toString());
}
}
}

1.2.10. 防止sql注入工具

  • 条件层过滤
/**
* SQL过滤
*
*/
public class SQLFilter { /**
* SQL注入过滤
* @param str 待验证的字符串
*/
public static String sqlInject(String str){
if(StringUtils.isBlank(str)){
return null;
}
//去掉'|"|;|\字符
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, "\"", "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\\", ""); //转换成小写
str = str.toLowerCase(); //非法字符
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"}; //判断是否包含非法字符
for(String keyword : keywords){
if(str.indexOf(keyword) != -1){
throw new RRException("包含非法字符");
}
} return str;
}
}

renren-fast后端源码参考-配置和对应工具的更多相关文章

  1. EDKII Build Process:EDKII项目源码的配置、编译流程[三]

    <EDKII Build Process:EDKII项目源码的配置.编译流程[3]>博文目录: 3. EDKII Build Process(EDKII项目源码的配置.编译流程) -> ...

  2. httpd的rpm包及源码安装配置

    httpd的rpm包及源码安装配置 1.rpm包安装 系统环境: [root@zhaochj ~]# cat /etc/issue CentOS release 6.4 (Final) Kernel ...

  3. vector源码(参考STL源码--侯捷):空间分配导致迭代器失效

    vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...

  4. 源码编译配置lnmp部署zabbix

    环境说明: [root@wcy ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@wcy ~]# uname -a Linux ...

  5. Eureka详解系列(四)--Eureka Client部分的源码和配置

    简介 按照原定的计划,我将分三个部分来分析 Eureka 的源码: Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系): Eureka Client ...

  6. Eureka详解系列(五)--Eureka Server部分的源码和配置

    简介 按照原定的计划,我将分三个部分来分析 Eureka 的源码: Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系): Eureka Client ...

  7. 实验 1:Mininet 源码安装和可视化拓扑工具

    实验 1:Mininet 源码安装和可视化拓扑工具 一.实验目的 掌握 Mininet 的源码安装方法和 miniedit 可视化拓扑生成工具. 二.实验任务 使用源码安装 Mininet 的 2.3 ...

  8. 读 Go 源码,可以试试这个工具

    原文链接: 读 Go 源码,可以试试这个工具 编程发展至今,从面向过程到面向对象,再到现在的面向框架.写代码变成了一件越来越容易的事情. 学习基础语法,看看框架文档,几天时间搞出一个小项目并不是一件很 ...

  9. Ueditor之前后端源码的学习和简单的研究

    这是我的项目目录 这里写图片描述 1.从访问路径http://localhost:8081/Test/_examples/simpleDemo.html,我们主要是要看看,富文本框被加载出来之前,会调 ...

随机推荐

  1. idea安装、配置及基本使用

    下载 下载地址:https://www.jetbrains.com/idea/download/#section=windows Ultimate为旗舰版,功能全面,插件丰富,按年收费. Commun ...

  2. gitlab的搭建和使用(转)

    工作当中常用的GitHub比较好用,但是安全性不是太强,因为github完全开源的,安全性不高 有空搞一下,先记录几个博客 https://yq.aliyun.com/articles/44531 h ...

  3. js 浮点数计算精度不准确问题

    或许很多人都遇到过,js 对小数的加.减.乘.除时经常得到一些奇怪的结果! 比如 :0.1 + 0.2 = 0.3  ? 这么一个简单的计算,当你用js 计算时会发现结果是:0.30000000000 ...

  4. MapReduce running in uber mode (jvm重用)

    原文 http://blog.csdn.net/samhacker/article/details/15692003 yarn-site.xml  主要是这几个参数 - mapreduce.job.u ...

  5. 函数$f(x+1)$和$f(x-1)$的奇偶性

    前言 廓清认知 1.函数\(y=f(x)\)的奇偶性 ①\(y=f(x)\)为奇函数,则满足\(f(-x)+f(x)=0\),即关于点\((0,0)\)对称: ②\(y=f(x)\)为偶函数,则满足\ ...

  6. 在eclipse中新建java问题报错:The type XXX cannot be resolved. It is indirectly referenced from required .class files

    在Eclipse中遇到The type XXX cannot be resolved. It is indirectly referenced from required .class files错误 ...

  7. 【BigData】Java基础_Eclipse配置自动补全new

    需求描述 在使用Eclipse的时候,每次new一个对象,写起来比较麻烦,以下是配置Eclipse,然后使用快捷键补全new方法的步骤,此配置使用官方属于叫做:配置自动分配局部变量 配置步骤 打开Wi ...

  8. 【BigData】Java基础_switch语句

    语法 switch(表达式) { case x: // 代码块 break; case y: // 代码块 break; default: // 代码块 } switch语句是这样工作的: switc ...

  9. C++ 派生类覆盖重载基类函数

    派生类希望基类重载函数可见,情况有三种: a)派生类中覆盖某个版本,则某个版本可见,全部都覆盖重写,则全部版本可见. b)派生类中一个也不覆盖,则全部基类版本可见. c)派生类需要添加新的重载版本,同 ...

  10. android webview 全屏100%显示图片

    这里引用 第三方类库 implementation 'org.jsoup:jsoup:1.10.2' 定义工具类 HtmlUtils import org.jsoup.Jsoup; import or ...