Commit 0dc48eb6 authored by zhouqian's avatar zhouqian

new hanguguan

parents
# han_gu_guan
\ No newline at end of file
This diff is collapsed.
package cn.quantgroup.xyqb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@ComponentScan(basePackages = {"cn.quantgroup.xyqb", "cn.quantgroup.cloudconfig"})
@EnableAutoConfiguration
@SpringBootApplication
@PropertySource(value = {"classpath:application.properties", "classpath:xyqb.properties"}, ignoreResourceNotFound = true)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 24 * 60 * 60)
@EnableCaching
@Configuration
@EnableAspectJAutoProxy
@EnableAsync
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
}
package cn.quantgroup.xyqb;
import com.google.gson.Gson;
/**
* Created by Miraculous on 15/7/5.
*/
public interface Constants {
// zero fill with 4 chars...
String ZERO_FILL_TEMPLATE = "%04d";
String PASSWORD_SALT = "_lkb";
String IMAGE_CAPTCHA_KEY = "img_captcha:";
String REDIS_CAPTCHA_KEY = "auth:";
String REDIS_CAPTCHA_KEY_PATTERN = REDIS_CAPTCHA_KEY + IMAGE_CAPTCHA_KEY + "*";
String CONFIG_CAPTCHA = "cfg_captcha_%";
// app 后端白名单
String CONFIG_CAPTCHA_WHITEIP_LIST = "cfg_captcha_white_ip_appbackend";
// 每个 IP 每分钟 captcha 限制
String CONFIG_CAPTCHA_PERIP_PERMIN = "cfg_captcha_per_ip_per_min";
// 是否启用万能验证码
String CONFIG_CAPTCHA_MAGIC_CODE_ENABLED = "cfg_captcha_magic_code_enabled";
Gson GSON = new Gson();
String REDIS_PREFIX_VERIFICATION_CODE = "verificationCode_";
/**
* redis中token的key值前缀
*/
String SESSION_PREFIX = "spring:session:sessions:";
interface Sms {
String VERIFICATION_CODE = "尊敬的用户,您本次的验证码为:%s,有效期10分钟。"; // 随机验证码
String BINDCARD_SMS = "用户您好,您已绑卡成功,将会在1-5个工作日内收到借款,请耐心等待。如有疑问,请致电400-002-0061,感谢您对我们的支持";//绑卡成功后的短信文案
String REPAY_SMS = "用户您好,您在信用钱包的本期账单已还款成功,保持良好的信用可升级为VIP用户,享更多特权,感谢您对信用钱包的支持";
}
interface Jr58 {
int ERROR_PHONE_NUMBER = 20007; // 手机号码格式不正确
int ERROR_ID_CARD = 20009; // 身份证格式不正确
int ERROR_ACCOUNT = 20010; // 授权账号为空
int ERROR_AUTH_TYPE = 20011; // 授权类型为空
}
interface Channel {
long LKB = 1; // 量化派
long JR58 = 175; // 58金融
String LKB_CODE = "0002"; // 量化派channnel_code
}
}
package cn.quantgroup.xyqb.aspect.captcha;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类名称:CaptchaRestriction
* 类描述:
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/12/23 12:15
* 修改人:
* 修改时间:15/12/23 12:15
* 修改备注:
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CaptchaRestriction {
}
package cn.quantgroup.xyqb.aspect.captcha;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.service.config.IConfigurationService;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService;
import com.octo.captcha.service.CaptchaServiceException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 类名称:CaptchaValidateAdvisor
* 类描述:
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/11/17 14:49
* 修改人:
* 修改时间:15/11/17 14:49
* 修改备注:
*/
@Aspect
@Component
public class CaptchaValidateAdvisor {
private static final Logger LOGGER = LoggerFactory.getLogger(CaptchaValidateAdvisor.class);
private static final String SUPER_CAPTCHA_ID = UUID.nameUUIDFromBytes("__QG_APPCLIENT_AGENT__".getBytes(Charset.forName("UTF-8"))).toString();
private static final String SUPER_CAPTCHA = "__SUPERQG__";
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
@Autowired
@Qualifier("customCaptchaService")
private AbstractManageableImageCaptchaService imageCaptchaService;
@Autowired
private IConfigurationService configurationService;
/**
* 自动化测试忽略验证码
*/
@Value("${xyqb.auth.captcha.autotest.enable:false}")
private boolean autoTestCaptchaEnabled;
/**
* 图形验证码切面
*/
@Pointcut("@annotation(cn.quantgroup.xyqb.aspect.captcha.CaptchaValidator)")
private void needCaptchaValidate() {
}
/**
* 客户端 Ip限制切面
*/
@Pointcut("@annotation(cn.quantgroup.xyqb.aspect.captcha.CaptchaRestriction)")
private void checkCaptchaRestriction() {
}
/**
* 根据 Ip 限制客户端 每分钟获取的图形二维码数量
*
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around("checkCaptchaRestriction()")
private Object preventCaptchaRequest(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object[] args = proceedingJoinPoint.getArgs();
String remoteIp = getClientIp(args);
if (remoteIp == null || clientIpInSafeList(remoteIp)) {
return proceedingJoinPoint.proceed();
}
String limitKey = "ipcaptcha:" + DateFormatUtils.format(new Date(), "yyyyMMddHHmm") + StringUtils.remove(StringUtils.remove(remoteIp, '.'), ':');
Long count = redisTemplate.opsForValue().increment(limitKey, 1);
// 1, 2, 3... <= 50
if (count == 1) {
redisTemplate.expire(limitKey, 1, TimeUnit.MINUTES);
}
Long captchaPerIpPerMin = getCaptchaPerIpPerMin();
if (count <= captchaPerIpPerMin) {
try {
Object proceed = proceedingJoinPoint.proceed();
if (proceed != null && proceed.getClass() == JsonResult.class) {
JsonResult jsonResult = (JsonResult) proceed;
String code = jsonResult.getCode();
// 如果生成验证码失败, 不计数
if (!"0000".equals(code)) {
redisTemplate.opsForValue().increment(limitKey, -1L);
}
}
return proceed;
} catch (Exception e) {
// 发生异常, 不计数
redisTemplate.opsForValue().increment(limitKey, -1L);
throw e;
}
}
LOGGER.error("获取验证码失败, 客户端[{}] 每分钟请求验证码超限制 : [{}]", remoteIp, captchaPerIpPerMin);
return JsonResult.buildErrorStateResult("您获取验证码较频繁,请稍候再试!", null);
}
private boolean clientIpInSafeList(String remoteIp) {
String value = configurationService.getValue(Constants.CONFIG_CAPTCHA_WHITEIP_LIST);
return !StringUtils.isBlank(value) && value.contains(remoteIp);
}
private String getClientIp(Object[] args) {
if (args.length < 2) {
return null;
}
String ip = String.valueOf(args[1]);
return StringUtils.isNotBlank(ip) ? ip : null;
}
/**
* 在受图形验证码保护的接口方法执行前, 执行图形验证码校验
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("needCaptchaValidate()")
private Object doCapchaValidate(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String registerFrom = Optional.ofNullable(request.getParameter("registerFrom")).orElse("");
String captchaId = Optional.ofNullable(request.getParameter("captchaId")).orElse("");
Object captchaValue = request.getParameter("captchaValue");
if (shouldSkipCaptchaValidate(registerFrom, captchaId, captchaValue)) {
LOGGER.info("使用超级图形验证码校验, registerFrom={}, clientIp={}", registerFrom, request.getRemoteAddr());
return pjp.proceed();
}
JsonResult result = JsonResult.buildSuccessResult("图形验证码错误, 请重新输入", "");
result.setBusinessCode("0002");
if (captchaValue != null) {
String captcha = String.valueOf(captchaValue);
// 忽略用户输入的大小写
captcha = StringUtils.lowerCase(captcha);
// 验证码校验
Boolean validCaptcha = false;
try {
validCaptcha = imageCaptchaService.validateResponseForID(Constants.IMAGE_CAPTCHA_KEY + captchaId, captcha);
} catch (CaptchaServiceException ex) {
LOGGER.error("验证码校验异常, {}, {}", ex.getMessage(), ex);
}
if (validCaptcha) {
return pjp.proceed();
}
}
return result;
}
private boolean shouldSkipCaptchaValidate(String registerFrom, String captchaId, Object captchaValue) {
boolean superCaptchaEnabled = Boolean.valueOf(configurationService.getValue(Constants.CONFIG_CAPTCHA_MAGIC_CODE_ENABLED));
// 如果启用了超级验证码功能, 检查超级验证码, 超级验证码区分大小写
if (superCaptchaEnabled && autoTestCaptchaEnabled) {
return true;
}
return superCaptchaEnabled
&& StringUtils.equals(SUPER_CAPTCHA_ID, String.valueOf(captchaId))
&& StringUtils.equals(SUPER_CAPTCHA, String.valueOf(captchaValue));
}
private Long getCaptchaPerIpPerMin() {
return Long.valueOf(configurationService.getValue(Constants.CONFIG_CAPTCHA_PERIP_PERMIN));
}
}
package cn.quantgroup.xyqb.aspect.captcha;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类名称:CaptchaValidate
* 类描述:
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/11/17 14:47
* 修改人:
* 修改时间:15/11/17 14:47
* 修改备注:
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CaptchaValidator {
}
package cn.quantgroup.xyqb.aspect.fplock;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Miraculous on 15/11/10.
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FPLock {
String uniqueName();
FPRestriction[] restrictions() default {};
}
package cn.quantgroup.xyqb.aspect.fplock;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
/**
* Created by Miraculous on 15/11/10.
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FPRestriction {
// 持续时间
int duration() default 1;
// 持续时间单位
TimeUnit type() default TimeUnit.MINUTES;
// 限制值, -1表示不限制
int limit() default -1;
// 使用可覆盖
boolean override() default true;
}
package cn.quantgroup.xyqb.config.captcha;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService;
import com.octo.captcha.engine.CaptchaEngine;
import com.octo.captcha.service.captchastore.CaptchaStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
/**
* 类名称:CaptchaConfig
* 类描述:
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/11/17 12:04
* 修改人:
* 修改时间:15/11/17 12:04
* 修改备注:
*/
@Configuration
public class CaptchaConfig {
@Bean
public CaptchaEngine initCaptchaEngine() {
return new CustomJCaptchaEngine();
}
@Bean
@Autowired
@Qualifier("stringRedisTemplate")
public CaptchaStore initStringCaptchaStore(RedisTemplate<String, String> stringRedisTemplate) {
return new RedisCaptchaStore(stringRedisTemplate);
}
@Bean(name = "customCaptchaService")
@Autowired
public AbstractManageableImageCaptchaService initCaptchaService(CaptchaStore captchaStore, CaptchaEngine captchaEngine) {
return new CustomJCaptchaService(captchaStore, captchaEngine);
}
}
package cn.quantgroup.xyqb.config.captcha;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.CustomGimpyFactory;
import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator;
import com.octo.captcha.component.image.color.RandomListColorGenerator;
import com.octo.captcha.component.image.color.SingleColorGenerator;
import com.octo.captcha.component.image.deformation.ImageDeformation;
import com.octo.captcha.component.image.deformation.ImageDeformationByFilters;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.DecoratedRandomTextPaster;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.textpaster.textdecorator.BaffleTextDecorator;
import com.octo.captcha.component.image.textpaster.textdecorator.TextDecorator;
import com.octo.captcha.component.image.wordtoimage.DeformedComposedWordToImage;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import java.awt.*;
import java.awt.image.ImageFilter;
/**
* 类名称:CustomJCaptchaEngine
* 类描述:
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/11/17 12:04
* 修改人:
* 修改时间:15/11/17 12:04
* 修改备注:
*/
public class CustomJCaptchaEngine extends ListImageCaptchaEngine {
private static final int MIN_WORD_LEN = 4;
private static final int MAX_WORD_LEN = 4;
@Override
protected void buildInitialFactories() {
int minWordLength = 4;
int maxWordLength = 4;
int fontSize = 16;
int imageWidth = 80;
int imageHeight = 28;
WordGenerator wordGenerator = new RandomWordGenerator("1234567890");
SingleColorGenerator colorGenerator = new SingleColorGenerator(Color.WHITE);
//文字干扰器--- 可以创建多个
BaffleTextDecorator baffleTextDecorator = new BaffleTextDecorator(1,colorGenerator, 1);//气泡干扰
// LineTextDecorator lineTextDecorator = new LineTextDecorator(1,colorGenerator, 1);//曲线干扰
// TextDecorator[] textDecorators = new TextDecorator[]{baffleTextDecorator, lineTextDecorator};
TextDecorator[] textDecorators = new TextDecorator[]{baffleTextDecorator};
TextPaster randomPaster = new DecoratedRandomTextPaster(minWordLength,
maxWordLength, new RandomListColorGenerator(new Color[]{
new Color(23, 170, 27), new Color(220, 34, 11),
new Color(23, 67, 172)}), textDecorators);
BackgroundGenerator background = new UniColorBackgroundGenerator(imageWidth, imageHeight, colorGenerator);
FontGenerator font = new RandomFontGenerator(fontSize, fontSize,
new Font[]{new Font("nyala", Font.BOLD, fontSize),
new Font("Bell MT", Font.PLAIN, fontSize),
new Font("Credit valley", Font.BOLD, fontSize)});
ImageDeformation postDef = new ImageDeformationByFilters(new ImageFilter[]{});
ImageDeformation backDef = new ImageDeformationByFilters(new ImageFilter[]{});
ImageDeformation textDef = new ImageDeformationByFilters(new ImageFilter[]{});
WordToImage word2image = new DeformedComposedWordToImage(font,
background, randomPaster, backDef, textDef, postDef);
addFactory(new CustomGimpyFactory(wordGenerator, word2image));
}
}
package cn.quantgroup.xyqb.config.captcha;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService;
import com.octo.captcha.Captcha;
import com.octo.captcha.engine.CaptchaEngine;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.captchastore.CaptchaStore;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale;
/**
* 类名称:CustomJCaptchaService
* 类描述:自定义的验证马实现服务
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/11/17 19:41
* 修改人:
* 修改时间:15/11/17 19:41
* 修改备注:
*/
public class CustomJCaptchaService extends AbstractManageableImageCaptchaService {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomJCaptchaService.class);
/*
* 验证码管理策略:
* 1, 生成验证码时, 会进行配额检查, 当达到配额时, 进行垃圾验证码清理
* 2, 一个验证码校验完成后, 不管成功失败, 都会直接失效, 删除?
* */
private static final Integer MIN_GUARANTED_STORAGE_DELAY_IN_SECONDS = 120; // 默认值, 执行垃圾清理时, 存活超过180s的验证码都会被清除
private static final Integer MAX_CAPTCHA_STORE_SIZE = 70000; // 最大容量, 默认值是10w
private static final Integer CAPTCHA_STORE_LOAD_BEFORE_GARBAGE_COLLECTION = 52500; // 配额, 超过此配额时执行一次垃圾清除, 默认值是:75000
public CustomJCaptchaService(CaptchaStore captchaStore, CaptchaEngine captchaEngine) {
this(captchaStore, captchaEngine, MIN_GUARANTED_STORAGE_DELAY_IN_SECONDS, MAX_CAPTCHA_STORE_SIZE, CAPTCHA_STORE_LOAD_BEFORE_GARBAGE_COLLECTION);
}
protected CustomJCaptchaService(CaptchaStore captchaStore, CaptchaEngine captchaEngine, int minGuarantedStorageDelayInSeconds, int maxCaptchaStoreSize, int captchaStoreLoadBeforeGarbageCollection) {
super(captchaStore, captchaEngine, minGuarantedStorageDelayInSeconds, maxCaptchaStoreSize, captchaStoreLoadBeforeGarbageCollection);
}
@Override
public long getCustomStoreSize() {
return this.store.getSize();
}
/**
* 重写校验, 需要将原来的 key 失效
*
* @param id
* @param response
* @return
* @throws CaptchaServiceException
*/
@Override
public Boolean validateResponseForID(String id, Object response) throws CaptchaServiceException {
if (StringUtils.isBlank(id)) {
return false;
}
boolean valid;
try {
Captcha captcha = this.store.getCaptcha(id);
if (null == captcha || captcha.hasGetChalengeBeenCalled()) {
return false;
}
valid = captcha.validateResponse(response);
} catch (Exception ex) {
LOGGER.warn("can not get captcha from redis");
valid = false;
}
this.getTimes().remove(id);
if(valid) {
addNumberOfCorrectResponse(1);
} else {
addNumberOfUncorrectResponse(1);
}
return valid;
}
/**
* 请求新的图形验证码
*
* @param ID
* @param locale
* @return
* @throws CaptchaServiceException
*/
public Object getChallengeForID(String ID, Locale locale) throws CaptchaServiceException {
Captcha captcha = this.generateAndStoreCaptcha(locale, ID);
Object challenge = this.getChallengeClone(captcha);
captcha.disposeChallenge();
return challenge;
}
@Override
public void garbageCollectCaptchaStore() {
super.garbageCollectCaptchaStore();
}
}
package cn.quantgroup.xyqb.config.captcha;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.SimpleCaptcha;
import com.octo.captcha.Captcha;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.captchastore.CaptchaStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.Collection;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
/**
* 类名称:RedisCaptchaStore
* 类描述:
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/12/17 06:39
* 修改人:
* 修改时间:15/12/17 06:39
* 修改备注:
*/
public class RedisCaptchaStore implements CaptchaStore {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisCaptchaStore.class);
private static final long DEFAULT_EXPIRED_IN = 120L;
private static final TimeUnit DEFAULT_EXPIRED_TIMEUNIT = TimeUnit.SECONDS;
protected RedisTemplate<String, String> stringRedisTemplate;
public RedisCaptchaStore(RedisTemplate<String, String> stringRedisTemplate) {
super();
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean hasCaptcha(String captchaId) {
return stringRedisTemplate.hasKey(buildCaptcharKey(captchaId));
}
@Override
public void storeCaptcha(String s, Captcha captcha) throws CaptchaServiceException {
stringRedisTemplate.opsForValue().set(buildCaptcharKey(s), ((SimpleCaptcha) captcha).getResponse(), DEFAULT_EXPIRED_IN, DEFAULT_EXPIRED_TIMEUNIT);
}
@Override
public void storeCaptcha(String s, Captcha captcha, Locale locale) throws CaptchaServiceException {
stringRedisTemplate.opsForValue().set(buildCaptcharKey(s), ((SimpleCaptcha) captcha).getResponse(), DEFAULT_EXPIRED_IN, DEFAULT_EXPIRED_TIMEUNIT);
}
@Override
public boolean removeCaptcha(String captchaId) {
stringRedisTemplate.delete(buildCaptcharKey(captchaId));
return true;
}
@Override
public Captcha getCaptcha(String captchaId) throws CaptchaServiceException {
return getFromRedisThenDel(captchaId);
}
@Override
public Locale getLocale(String captchaId) throws CaptchaServiceException {
return Locale.CHINA;
}
@Override
public int getSize() {
return getKeys().size();
}
@Override
public Collection getKeys() {
return stringRedisTemplate.keys(Constants.REDIS_CAPTCHA_KEY_PATTERN);
}
@Override
public void empty() {
}
@Override
public void initAndStart() {
}
@Override
public void cleanAndShutdown() {
}
private Captcha getFromRedis(String captchaId) {
Object value = stringRedisTemplate.opsForValue().get(buildCaptcharKey(captchaId));
return value != null ? new SimpleCaptcha(captchaId, String.valueOf(value)) : null;
}
private Captcha getFromRedisThenDel(String captchaId) {
String captcharKey = buildCaptcharKey(captchaId);
Object value = stringRedisTemplate.opsForValue().get(captcharKey);
stringRedisTemplate.delete(captcharKey);
return value != null ? new SimpleCaptcha(captchaId, String.valueOf(value)) : null;
}
protected String buildCaptcharKey(String captchaId) {
return Constants.REDIS_CAPTCHA_KEY + captchaId;
}
}
package cn.quantgroup.xyqb.config.data;
/**
* Created by Miraculous on 2016/11/16.
*/
import cn.quantgroup.cloudconfig.SafeValue;
import cn.quantgroup.xyqb.util.ApplicationContextHolder;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
/**
* Created by Miraculous on 2016/11/14.
*/
@Configuration
@EnableJpaRepositories(basePackages = "cn.quantgroup.xyqb.repository")
@EnableTransactionManagement
public class JpaConfig {
@SafeValue("xyqb.data.mysql.jdbc-url")
private String xyqbJdbcUrl;
@SafeValue("xyqb.data.mysql.password")
private String password;
@SafeValue("xyqb.data.mysql.user")
private String user;
@Value("${xyqb.data.mysql.max-pool-size}")
private Integer maxPoolSize;
@Bean
@DependsOn(value = "dataSource")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(ApplicationContextHolder.getBean("dataSource"));
entityManager.setPackagesToScan("cn.quantgroup.xyqb");
entityManager.setPersistenceUnitName("dataSource");
Properties properties = new Properties();
properties.put("hibernate.jdbc.batch_size", 30);
properties.put("hibernate.order_inserts", true);
properties.put("hibernate.order_updates", true);
entityManager.setJpaProperties(properties);
entityManager.setJpaVendorAdapter(jpaVendorAdapter());
entityManager.afterPropertiesSet();
return entityManager.getObject();
}
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(xyqbJdbcUrl);
config.setPassword(password);
config.setUsername(user);
config.setMaximumPoolSize(maxPoolSize);
config.setMinimumIdle(20);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
return new HikariDataSource(config);
}
private JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(false);
hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
return hibernateJpaVendorAdapter;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
package cn.quantgroup.xyqb.config.data;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;
/**
* Created by Miraculous on 15/7/4.
*/
@Configuration
public class RedisConfig {
@Value("${xyqb.data.redis.defaultExpiration}")
private Long defaultExpiration;
@Value("${xyqb.redis.master.host}")
private String masterHost;
@Value("${xyqb.redis.master.port}")
private int masterPort;
@Value("${xyqb.redis.master.name}")
private String masterName;
@Value("${xyqb.redis.sentinel1.host}")
private String sentinel1Host;
@Value("${xyqb.redis.sentinel1.port}")
private int sentinel1port;
@Value("${xyqb.redis.sentinel2.host}")
private String sentinel2Host;
@Value("${xyqb.redis.sentinel2.port}")
private int sentinel2port;
@Value("${xyqb.redis.sentinel3.host}")
private String sentinel3Host;
@Value("${xyqb.redis.sentinel3.port}")
private int sentinel3port;
private RedisConnectionFactory generateDevConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(masterHost);
factory.setPort(masterPort);
factory.setUsePool(true);
factory.setConvertPipelineAndTxResults(true);
JedisPoolConfig poolConfig = generatePoolConfig();
factory.setPoolConfig(poolConfig);
factory.afterPropertiesSet();
return factory;
}
private RedisConnectionFactory generateReleaseConnectionFactory() {
RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration();
RedisNode master = new RedisNode(masterHost, masterPort);
master.setName(masterName);
Set<RedisNode> sentinels = new HashSet<>();
RedisNode sentinel1 = new RedisNode(sentinel1Host, sentinel1port);
RedisNode sentinel2 = new RedisNode(sentinel2Host, sentinel2port);
RedisNode sentinel3 = new RedisNode(sentinel3Host, sentinel3port);
sentinels.add(sentinel1);
sentinels.add(sentinel2);
sentinels.add(sentinel3);
sentinelConfiguration.setMaster(master);
sentinelConfiguration.setSentinels(sentinels);
JedisPoolConfig poolConfig = generatePoolConfig();
JedisConnectionFactory factory = new JedisConnectionFactory(sentinelConfiguration, poolConfig);
factory.setHostName(masterHost);
factory.setPort(masterPort);
factory.setTimeout(5000);
factory.setUsePool(true);
factory.setConvertPipelineAndTxResults(true);
factory.afterPropertiesSet();
return factory;
}
private JedisPoolConfig generatePoolConfig() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMinIdle(20);
poolConfig.setMaxTotal(300);
poolConfig.setMaxWaitMillis(5000);
poolConfig.setTestOnBorrow(true);
return poolConfig;
}
@Bean(name = "redisConnectionFactory")
RedisConnectionFactory factory() {
if (StringUtils.isEmpty(masterName)) {
return generateDevConnectionFactory();
} else {
return generateReleaseConnectionFactory();
}
}
@Bean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(
RedisConnectionFactory factory) {
final RedisTemplate<String, Object> template = new RedisTemplate<>();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
template.setEnableTransactionSupport(false);
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setValueSerializer(jdkSerializationRedisSerializer);
template.setDefaultSerializer(jdkSerializationRedisSerializer);
template.setConnectionFactory(factory);
return template;
}
@Bean(name = "stringRedisTemplate")
public RedisTemplate<String, String> stringRedisTemplate(
RedisConnectionFactory factory) {
final RedisTemplate<String, String> template = new RedisTemplate<>();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
template.setEnableTransactionSupport(true);
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setValueSerializer(jdkSerializationRedisSerializer);
template.setDefaultSerializer(jdkSerializationRedisSerializer);
template.setConnectionFactory(factory);
return template;
}
@Bean(name = "cacheManager")
public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setDefaultExpiration(defaultExpiration);
cacheManager.setUsePrefix(true);
return cacheManager;
}
}
package cn.quantgroup.xyqb.config.http;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import javax.net.ssl.SSLContext;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BestMatchSpecFactory;
import org.apache.http.impl.cookie.BrowserCompatSpec;
import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.session.web.http.HeaderHttpSessionStrategy;
import org.springframework.web.filter.CharacterEncodingFilter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* Created by Miraculous on 15/7/12.
*/
@Configuration
public class HttpConfig {
@Bean
HeaderHttpSessionStrategy sessionStrategy() {
return new HeaderHttpSessionStrategy();
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
registrationBean.setFilter(characterEncodingFilter);
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
registrationBean.setOrder(Integer.MIN_VALUE);
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
/**
* 该方法主要对对象json序列化产生影响,其功能如下:
* 1. 禁用缩进输出
* 2. 日期格式排版
* 3. null被过滤掉
* 4. 将enum转为其ordinal
*
* @return Jackson2ObjectMapperBuilder
*/
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.indentOutput(false)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.defaultViewInclusion(false)
.serializationInclusion(JsonInclude.Include.NON_NULL)
.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_INDEX,
DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
return builder;
}
// hack spring mvc.
@Bean
public IntegerToEnumConverterFactory getIntegerToEnumConverterFactory(
ConverterRegistry defaultConversionService, ConverterRegistry mvcConversionService, ConverterRegistry integrationConversionService) {
IntegerToEnumConverterFactory factory = new IntegerToEnumConverterFactory();
defaultConversionService.removeConvertible(String.class, Enum.class);
mvcConversionService.removeConvertible(String.class, Enum.class);
integrationConversionService.removeConvertible(String.class, Enum.class);
defaultConversionService.addConverterFactory(factory);
mvcConversionService.addConverterFactory(factory);
integrationConversionService.addConverterFactory(factory);
return factory;
}
@Bean(name = "httpClient")
public CloseableHttpClient httpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// socket factory
ConnectionSocketFactory plainSocketFactory = new PlainConnectionSocketFactory();
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(
null, (x509Certificates, authType) -> true).build();
LayeredConnectionSocketFactory sslSocketFactory =
new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier());
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainSocketFactory)
.register("https", sslSocketFactory).build();
// cookie specification
Registry<CookieSpecProvider> cookieSpecProviderRegistry = RegistryBuilder.<CookieSpecProvider>create()
.register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
.register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory())
.register("easy", httpContext -> new BrowserCompatSpec() {
public void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException {
}
}).build();
// connection manager
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connectionManager.setMaxTotal(10000);
connectionManager.setDefaultMaxPerRoute(1000);
// retry handler
HttpRequestRetryHandler retryHandler = new StandardHttpRequestRetryHandler(3, false);
// keep alive strategy
ConnectionKeepAliveStrategy keepAliveStrategy = new DefaultConnectionKeepAliveStrategy();
// httpclient
return HttpClients.custom()
.setConnectionManager(connectionManager)
.setRetryHandler(retryHandler)
.setKeepAliveStrategy(keepAliveStrategy)
.setDefaultCookieSpecRegistry(cookieSpecProviderRegistry).build();
}
}
package cn.quantgroup.xyqb.config.http;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
/**
* Created by Miraculous on 15/7/12.
*/
final class IntegerToEnumConverterFactory implements ConverterFactory<String, Enum> {
IntegerToEnumConverterFactory() {
}
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
Class<?> enumType = targetType;
while (enumType != null && !enumType.isEnum()) {
enumType = enumType.getSuperclass();
}
if (enumType == null) {
throw new IllegalArgumentException("The target type " + targetType.getName() + " does not refer to an enum");
} else {
return new IntegerToEnumConverterFactory.IntegerToEnum(enumType);
}
}
private class IntegerToEnum<T extends Enum> implements Converter<String, T> {
private final Class<T> enumType;
public IntegerToEnum(Class<T> enumType) {
this.enumType = enumType;
}
public T convert(String source) {
T[] ts = enumType.getEnumConstants();
int ordinal = Integer.parseInt(source);
return ordinal < ts.length && ordinal >= 0 ? ts[ordinal] : null;
}
}
}
\ No newline at end of file
package cn.quantgroup.xyqb.config.security;
import cn.quantgroup.xyqb.exception.PasswordErrorException;
import cn.quantgroup.xyqb.exception.UserNotExistException;
import cn.quantgroup.xyqb.exception.VerificationCodeErrorException;
import cn.quantgroup.xyqb.model.JsonResult;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by Miraculous on 15/7/5.
*/
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
JsonResult result = JsonResult.buildErrorStateResult("登录失败", null);
if (e instanceof UserNotExistException || e.getCause() instanceof UserNotExistException) {
result.setMsg("该用户名不存在,<br/>请重新输入或注册新账号。");
} else if (e instanceof PasswordErrorException || e.getCause() instanceof PasswordErrorException) {
result.setMsg("您的密码输入错误,<br/>请重新输入。");
}
response.setStatus(HttpStatus.SC_OK);
response.setContentType("application/javascript; charset=utf-8");
PrintWriter out = response.getWriter();
out.println(GSON.toJson(result));
out.flush();
out.close();
}
}
package cn.quantgroup.xyqb.config.security;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.exception.PasswordErrorException;
import cn.quantgroup.xyqb.filter.AppAuthenticatedFilter;
import cn.quantgroup.xyqb.filter.Jr58AuthenticatedFilter;
import cn.quantgroup.xyqb.filter.SmsLoginAuthenticatedFilter;
import cn.quantgroup.xyqb.util.PasswordUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
/**
* Created by Miraculous on 15/7/4.
*/
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
@Autowired
private Jr58AuthenticatedFilter jr58AuthenticatedFilter;
@Autowired
private AppAuthenticatedFilter appAuthenticatedFilter;
@Autowired
private SmsLoginAuthenticatedFilter smsLoginAuthenticatedFilter;
@Value("${xyqb.security.allowedRoutes}")
private String allowedRoutes;
@Override
protected void configure(HttpSecurity http) throws Exception {
String[] allowedRoutesArr = allowedRoutes.split(",");
http
.csrf().disable()
.authorizeRequests()
.antMatchers(allowedRoutesArr).permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(new RESTAuthenticationEntryPoint())
.and()
.addFilter(jr58AuthenticatedFilter)
.addFilter(appAuthenticatedFilter)
.addFilter(smsLoginAuthenticatedFilter)
.logout();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence rawPass) {
return PasswordUtil.MD5(rawPass.toString().toLowerCase() + Constants.PASSWORD_SALT);
}
@Override
public boolean matches(CharSequence rawPass, String password) {
if (StringUtils.isEmpty(password)) {
throw new PasswordErrorException("密码错误");
}
if (password.equals(PasswordUtil.MD5(rawPass.toString().toLowerCase() + Constants.PASSWORD_SALT))) {
return true;
}
throw new PasswordErrorException("密码错误");
}
});
}
@Override
public UserDetailsService userDetailsServiceBean() {
return userDetailsService;
}
}
package cn.quantgroup.xyqb.config.web;
import cn.quantgroup.xyqb.interceptors.ChannelIdInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Created by Miraculous on 15/7/10.
*/
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ChannelIdInterceptor()).addPathPatterns("/**");
}
}
package cn.quantgroup.xyqb.controller;
import cn.quantgroup.xyqb.exception.NullUserException;
import cn.quantgroup.xyqb.exception.UserNotExistException;
import cn.quantgroup.xyqb.exception.VerificationCodeErrorException;
import cn.quantgroup.xyqb.model.JsonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* Created by Miraculous on 15/7/6.
* 出现异常,进入这个handler。
*/
@ControllerAdvice
@RestController
public class ExceptionHandlingController implements IBaseController {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandlingController.class);
private static final JsonResult EXCEPTION_RESULT = new JsonResult("internal error", 500L, "");
@ExceptionHandler(NullUserException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public JsonResult nullUserException(NullUserException nue) {
return new JsonResult(nue.getMessage(), 401L, null);
}
/**
* 验证码登陆异常
*
* @param vce
* @return
*/
@ExceptionHandler(VerificationCodeErrorException.class)
public JsonResult verificationCodeErrorException(VerificationCodeErrorException vce) {
return JsonResult.buildErrorStateResult(vce.getMessage(), null, 1L);
}
@ExceptionHandler(UserNotExistException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public JsonResult userNotExistException(UserNotExistException unee) {
return new JsonResult(unee.getMessage(), 401L, null);
}
@ExceptionHandler(Exception.class)
public JsonResult exceptionOccurs(Exception e) {
HttpServletRequest request = getRequest();
String uri = request.getRequestURI();
String registerFrom = request.getParameter("registerFrom");
LOGGER.error("接口异常 URI:{}, registerFrom:{}", uri, registerFrom, e);
return EXCEPTION_RESULT;
}
}
package cn.quantgroup.xyqb.controller;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.model.AuthenticationUserDetail;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* Created by Miraculous on 15/7/5.
*/
public interface IBaseController {
default User getCurrentUser() {
if (null == SecurityContextHolder.getContext().getAuthentication()) {
return null;
}
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return (AuthenticationUserDetail) principal;
}
default HttpSession getSession() {
HttpSession session = null;
try {
session = getRequest().getSession();
} catch (Exception e) {
e.getStackTrace();
}
return session;
}
default Long getChannelId() {
return getNumber("channelId");
}
default Long getCreatedFrom() {
return getNumber("createdFrom");
}
default Long getNumber(String name) {
HttpSession session = getSession();
try {
Long number = Long.valueOf(session.getAttribute(name).toString());
return number;
} catch (Exception e) {
e.getStackTrace();
}
return 0L;
}
default void setChannelId(Long channelId) {
HttpSession session = getSession();
if (session != null) {
session.setAttribute("channleId", channelId);
}
}
default String getAppChannel() {
HttpSession session = getSession();
Object appChannel = session.getAttribute("appChannel");
if(appChannel == null){
return null;
}
return appChannel.toString();
}
default HttpServletRequest getRequest() {
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
return attrs.getRequest();
}
default String getIp() {
HttpServletRequest request = getRequest();
String ip = request.getHeader("x-real-ip");
if (StringUtils.isEmpty(ip)) {
ip = request.getRemoteAddr();
}
//过滤反向代理的ip
String[] stemps = ip.split(",");
if (stemps != null && stemps.length >= 1) {
//得到第一个IP,即客户端真实IP
ip = stemps[0];
}
ip = ip.trim();
if (ip.length() > 23) {
ip = ip.substring(0, 23);
}
return ip;
}
}
package cn.quantgroup.xyqb.controller.external.captcha;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 类名称:ImgCaptchaController
* 类描述:图形验证码控制器
*
* @author 李宁
* @version 1.0.0
* 创建时间:15/11/17 11:49
* 修改人:
* 修改时间:15/11/17 11:49
* 修改备注:
*/
@RestController
@RequestMapping("/api")
public class ImageCaptchaController implements IBaseController {
private static final Logger LOGGER = LoggerFactory.getLogger(ImageCaptchaController.class);
private static final String IMAGE_FORMAT_PNG = "png";
private static final String IMG_BASE64_PATTREN = "data:image/" + IMAGE_FORMAT_PNG + ";base64,%s";
@Autowired
@Qualifier("customCaptchaService")
private AbstractManageableImageCaptchaService imageCaptchaService;
@ModelAttribute("clientIp")
public String initClientIp() {
return getIp();
}
/**
* 获取验证码
* 默认匹配 GET /captcha, 提供4位数字和字母混合图片验证码
*
* @return
*/
@RequestMapping(value = "/captcha")
public JsonResult fetchCaptcha(HttpServletRequest request, @ModelAttribute("clientIp") String clientIp) {
String imageId = UUID.randomUUID().toString();
BufferedImage challenge = imageCaptchaService.getImageChallengeForID(Constants.IMAGE_CAPTCHA_KEY + imageId, request.getLocale());
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
boolean write = ImageIO.write(challenge, IMAGE_FORMAT_PNG, jpegOutputStream);
} catch (IOException e) {
e.printStackTrace();
return JsonResult.buildErrorStateResult("", "fail");
}
String imageBase64 = Base64.encodeBase64String(jpegOutputStream.toByteArray());
Map<String, String> data = new HashMap<>();
data.put("imageId", imageId);
data.put("image", String.format(IMG_BASE64_PATTREN, imageBase64));
return JsonResult.buildSuccessResult("", data);
}
}
package cn.quantgroup.xyqb.controller.external.user;
import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.exception.NullUserException;
import cn.quantgroup.xyqb.model.AuthBean;
import cn.quantgroup.xyqb.model.JsonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
/**
* @author mengfan.feng
* @time 2015-10-27 11:41
*/
@RestController
@RequestMapping("/app")
public class AppController implements IBaseController {
private static final Logger LOGGER = LoggerFactory.getLogger(AppController.class);
/**
* 第三方用户登录
*
* @param user
* @return
*/
@RequestMapping("/login")
public JsonResult login(Principal user, HttpServletRequest request) {
if (user == null) {
throw new NullUserException();
}
AuthBean bean = new AuthBean(getRequest().getSession().getId(), user);
LOGGER.info("第三方用户登录成功, loginFrom:{}, phoneNo:{},appChannel:{}", request.getParameter("registerFrom"), request.getParameter("phoneNo"), getAppChannel());
return new JsonResult(bean);
}
}
package cn.quantgroup.xyqb.controller.external.user;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.entity.UserDetail;
import cn.quantgroup.xyqb.entity.UserDetailRet;
import cn.quantgroup.xyqb.entity.UserRet;
import cn.quantgroup.xyqb.model.IdType;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.repository.IUserDetailRepository;
import cn.quantgroup.xyqb.repository.IUserRepository;
import cn.quantgroup.xyqb.service.auth.IIdCardService;
import cn.quantgroup.xyqb.service.user.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.sql.Timestamp;
import java.text.ParseException;
/**
* Created by Miraculous on 2016/12/19.
*/
@RestController
@RequestMapping("/innerapi")
public class InnerController {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(InnerController.class);
@Autowired
private IUserService userService;
@Autowired
private IUserRepository userRepository;
@Autowired
private IUserDetailRepository userDetailRepository;
@Autowired
private IIdCardService idCardService;
@RequestMapping("/user/search/phoneNo")
public JsonResult findByPhoneNo(String phoneNo) {
User user = userService.findByPhoneInDb(phoneNo);
if (user == null) {
return JsonResult.buildErrorStateResult("", null);
}
UserRet userRet = UserRet.getUserRet(user);
return JsonResult.buildSuccessResult("", userRet);
}
@RequestMapping("/user/search/uuid")
public JsonResult findByUuid(String uuid) {
User user = userService.findByUuidInDb(uuid);
if (user == null) {
return JsonResult.buildErrorStateResult("", null);
}
UserRet userRet = UserRet.getUserRet(user);
return JsonResult.buildSuccessResult("", userRet);
}
@RequestMapping("/user/save")
public JsonResult saveUser(
String phoneNo, Long registeredFrom, Long createdAt, Long updatedAt,
String password, String uuid) {
//参数验证
if(StringUtils.isBlank(phoneNo)){
return JsonResult.buildErrorStateResult("用户手机号不能为空.", null);
}
if(registeredFrom == null){
registeredFrom = 0L;
}
if(StringUtils.isBlank(password)){
password = "";
}
if(StringUtils.isBlank(uuid)){
return JsonResult.buildErrorStateResult("用户uuid为空.", null);
}
if(createdAt == 0L || updatedAt == 0L){
createdAt = System.currentTimeMillis();
updatedAt = System.currentTimeMillis();
}
User user = userRepository.findByPhoneNo(phoneNo);
if (user == null) {
user = new User();
}
user.setPhoneNo(phoneNo);
user.setCreatedAt(new Timestamp(createdAt));
user.setUpdatedAt(new Timestamp(updatedAt));
user.setEnable(true);
user.setRegisteredFrom(registeredFrom);
user.setUuid(uuid);
user.setPassword(password);
user = userRepository.save(user);
UserRet userRet = null;
if(user != null){
userRet = UserRet.getUserRet(user);
}
return JsonResult.buildSuccessResult(null, userRet);
}
/**
* 保存用户详细信息
* @param userId
* @param phoneNo
* @param name
* @param idNo
* @param email
* @return
*/
@RequestMapping("/user_detail/save")
public JsonResult saveUserDetail(Long userId, String phoneNo, String name, String idNo,
String email){
//参数验证
if(userId == null || userId == 0L){
return JsonResult.buildErrorStateResult("用户id为空.", null);
}
if(StringUtils.isBlank(phoneNo)){
return JsonResult.buildErrorStateResult("用户手机号为空.", null);
}
if(StringUtils.isBlank(name)){
return JsonResult.buildErrorStateResult("用户名为空.", null);
}
if(StringUtils.isBlank(idNo)){
return JsonResult.buildErrorStateResult("用户身份证为空.", null);
}
UserDetail userDetail = new UserDetail();
userDetail.setUserId(userId);
userDetail.setName(name);
userDetail.setPhoneNo(phoneNo);
userDetail.setIdNo(idNo);
Timestamp time = new Timestamp(System.currentTimeMillis());
userDetail.setCreatedAt(time);
userDetail.setUpdatedAt(time);
userDetail.setIdType(IdType.ID_CARD);
try {
userDetail.setGender(idCardService.getIdCardInfo(idNo).getGender());
} catch (ParseException e) {
LOGGER.error("根据身份证获取性别出错,错误信息:" + e);
return JsonResult.buildErrorStateResult(null, null);
}
userDetail.setEmail(email);
userDetail = userDetailRepository.saveAndFlush(userDetail);
if(userDetail != null){
return JsonResult.buildSuccessResult(null, UserDetailRet.getUserDetail(userDetail));
}
return JsonResult.buildErrorStateResult("",null);
}
/**
* 根据用户id查询用户的详细信息
* @param userId
* @return
*/
@RequestMapping("/user_detail/search/userId")
public JsonResult findUserDetailByUserId(Long userId){
UserDetail userDetail = userDetailRepository.findByUserId(userId);
if(userDetail != null){
return JsonResult.buildSuccessResult(null, UserDetailRet.getUserDetail(userDetail));
}
return JsonResult.buildErrorStateResult("", null);
}
@RequestMapping("/user/search/userId")
public JsonResult findUserByUserId(Long userId){
User user = userRepository.findById(userId);
if(user != null){
return JsonResult.buildSuccessResult(null, UserRet.getUserRet(user));
}
return JsonResult.buildErrorStateResult("", null);
}
@RequestMapping("/user_detail/search/phone")
public JsonResult findUserDetailByPhone(String phoneNo){
UserDetail userDetail = userDetailRepository.findByPhoneNo(phoneNo);
if(userDetail != null){
return JsonResult.buildSuccessResult(null, UserDetailRet.getUserDetail(userDetail));
}
return JsonResult.buildErrorStateResult("", null);
}
@RequestMapping("/user_detail/update/qq")
public JsonResult updateUserQQ(String qq, Long userId){
if(StringUtils.isEmpty(qq) || userId == null || userId == 0L){
return JsonResult.buildErrorStateResult("参数校验失败,qq或用户id为空", null);
}
userDetailRepository.updateUserQQ(qq, userId);
return JsonResult.buildSuccessResult(null, null);
}
}
\ No newline at end of file
package cn.quantgroup.xyqb.controller.external.user;
import cn.quantgroup.user.IUserSdkService;
import cn.quantgroup.user.UserSdkServiceFactory;
import cn.quantgroup.user.UserSysResult;
import cn.quantgroup.user.bean.UserDetailSaveBean;
import cn.quantgroup.user.retbean.XUserDetail;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.entity.UserDetail;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.UserModel;
import cn.quantgroup.xyqb.service.user.IUserService;
import cn.quantgroup.xyqb.util.Utils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
/**
* 同步用户数据,第三方模块访问时
* Created by Miraculous on 15/12/29.
*/
@RestController
@RequestMapping("/api/sync")
public class SyncUserController {
@Autowired
private IUserService userService;
/*@Autowired
private IUserDetailRepository userDetailRepository;*/
@Autowired
@Qualifier("httpClient")
private CloseableHttpClient httpClient;
@Value("${usersys.url}")
private String userSysUrl;
private IUserSdkService userSdkService;
@PostConstruct
private void init() {
userSdkService = UserSdkServiceFactory.generateSDKService(userSysUrl, httpClient);
}
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> stringRedisTemplate;
@RequestMapping("/user")
public JsonResult fetchUser(String key, String phoneNo) {
if (StringUtils.isEmpty(key) || !"abc1234".equals(key)) {
return JsonResult.buildErrorStateResult(null, null);
}
if (StringUtils.isEmpty(phoneNo)) {
return JsonResult.buildErrorStateResult(null, null);
}
User user = userService.findByPhone(phoneNo);
if (null == user) {
return JsonResult.buildErrorStateResult(null, null);
}
UserSysResult<XUserDetail> userSysResult = userSdkService.findUserDetailByUserId(user.getId());
// if(!userSysResult.isSuccess() || userSysResult.getData() == null){
// return JsonResult.buildErrorStateResult(null, null);
// }
UserModel userModel = new UserModel(user, Utils.xuserDetail2UserDetail(userSysResult.getData()));
return JsonResult.buildSuccessResult(null, userModel);
/*UserDetail detail = userDetailRepository.findByUserId(user.getId());
if (null == detail) {
// FIXME: 16/4/15 前期不对身份证强制要求.后期对修改
// return JsonResult.buildErrorStateResult(null, null);
}
UserModel userModel = new UserModel(user, detail);
return JsonResult.buildSuccessResult(null, userModel);*/
}
@RequestMapping("/save_detail")
public JsonResult saveUserDetail(String key, UserDetail userDetail) {
if (StringUtils.isEmpty(key) || !"abc1234".equals(key)) {
return JsonResult.buildErrorStateResult(null, null);
}
String phoneNo = userDetail.getPhoneNo();
User user = userService.findByPhone(phoneNo);
if (null == user) {
return JsonResult.buildErrorStateResult(null, null);
}
userDetail.setId(null);
userDetail.setUserId(user.getId());
//修改代码
UserDetailSaveBean saveBean = new UserDetailSaveBean();
saveBean.setName(userDetail.getName());
saveBean.setEmail(userDetail.getEmail());
saveBean.setUserId(user.getId());
saveBean.setPhoneNo(userDetail.getPhoneNo());
saveBean.setIdNo(userDetail.getIdNo());
userSdkService.saveUserDetail(saveBean);
return JsonResult.buildSuccessResult(null, null);
/*userDetailRepository.saveAndFlush(userDetail);
return JsonResult.buildSuccessResult(null, null);*/
}
@RequestMapping("/user_uuid")
public JsonResult fetchUserByUuid(String key, String uuid) {
if (StringUtils.isEmpty(key) || !"abc1234".equals(key)) {
return JsonResult.buildErrorStateResult(null, null);
}
if (StringUtils.isEmpty(uuid)) {
return JsonResult.buildErrorStateResult(null, null);
}
User user = userService.findByUuid(uuid);
if (null == user) {
return JsonResult.buildErrorStateResult(null, null);
}
UserSysResult<XUserDetail> userSysResult = userSdkService.findUserDetailByUserId(user.getId());
if(!userSysResult.isSuccess() || userSysResult.getData() == null){
}
UserModel userModel = new UserModel(user, Utils.xuserDetail2UserDetail(userSysResult.getData()));
return JsonResult.buildSuccessResult(null, userModel);
/*UserDetail detail = userDetailRepository.findByUserId(user.getId());
if (null == detail) {
// FIXME: 16/4/15 前期不对身份证强制要求.后期对修改
// return JsonResult.buildErrorStateResult(null, null);
}
UserModel userModel = new UserModel(user, detail);
return JsonResult.buildSuccessResult(null, userModel);*/
}
}
package cn.quantgroup.xyqb.controller.external.user;
import cn.quantgroup.sms.SmsSender;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.service.api.IUserApiService;
import cn.quantgroup.xyqb.service.user.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by FrankChow on 15/12/16.
*/
@RestController
@RequestMapping("/api")
public class UserApiController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserApiController.class);
@Autowired
private IUserApiService userApiService;
@Autowired
private IUserService userService;
@RequestMapping("/user/check")
public JsonResult userImportCheck(String phoneNo, String registerFrom) {
if ("244".equals(registerFrom)) {
LOGGER.info("[user_import_check]用户导入检查拒绝。phoneNo=[{}], registerFrom=[{}]", phoneNo, registerFrom);
return JsonResult.buildErrorStateResult("用户导入检查拒绝", false);
}
if (StringUtils.isEmpty(phoneNo) || StringUtils.isEmpty(registerFrom)) {
LOGGER.error("[user_import_check]检查传入的参数,参数不全。phoneNo=[{}], registerFrom=[{}]", phoneNo, registerFrom);
return JsonResult.buildErrorStateResult("检查传入的参数,参数不全。", null);
}
boolean checkPassed = userApiService.userImportCheck(phoneNo);
if (checkPassed) {
LOGGER.info("[user_import_check]用户可以导入。phoneNo=[{}], registerFrom=[{}]", phoneNo, registerFrom);
return JsonResult.buildSuccessResult("用户可以导入", checkPassed);
}
LOGGER.info("[user_import_check]用户导入检查拒绝。phoneNo=[{}], registerFrom=[{}]", phoneNo, registerFrom);
return JsonResult.buildErrorStateResult("用户导入检查拒绝", checkPassed);
}
@RequestMapping("/user/is_passwd_set")
public JsonResult isPasswordSet(String key, String phoneNo) {
if (!"abc1234".equals(key) || StringUtils.isEmpty(phoneNo)) {
return JsonResult.buildErrorStateResult(null, null);
}
User user = userService.findByPhone(phoneNo);
if (null == user) {
return JsonResult.buildErrorStateResult(null, null);
}
if (StringUtils.length(user.getPassword()) == 32) {
return JsonResult.buildSuccessResult(null, null);
}
return JsonResult.buildErrorStateResult(null, null, 2L);
}
}
package cn.quantgroup.xyqb.controller.internal.sms;
import cn.quantgroup.sms.ConfirmableMsg;
import cn.quantgroup.sms.SendAndForgetMsg;
import cn.quantgroup.sms.SmsSender;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.aspect.captcha.CaptchaValidator;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.sms.SmsResult;
import cn.quantgroup.xyqb.service.sms.ISmsService;
import cn.quantgroup.xyqb.util.ValidationUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Created by FrankChow on 15/7/6.
*/
@RestController
@RequestMapping("/api/sms")
public class SmsController {
private static final Logger LOGGER = LoggerFactory.getLogger(SmsController.class);
@Autowired
private ISmsService smsService;
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
@Value("${sms.is.debug}")
private boolean smsIsDebug;
private static final Random random = new Random();
private static final long EXPIRE_MINUTES = 10;
/**
* 短信验证码: for H5
* 使用 @FPLock 注解并加入自定义限制参数, 做针对手机号的发送次数限制
*/
@CaptchaValidator
@RequestMapping("/send_sms_verification_code")
public JsonResult verifyPhoneNoH5(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom) {
LOGGER.info("注册-发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom);
return sendVerificationCode2(phoneNo);
}
@CaptchaValidator
@RequestMapping("/send_reset_code")
public JsonResult resetPasswordH5(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom) {
LOGGER.info("重置密码-发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom);
return sendVerificationCode2(phoneNo);
}
/**
* 快速登陆发送验证码
*
* @param phoneNo
* @param registerFrom
* @return
*/
@CaptchaValidator
@RequestMapping("/send_login_code")
public JsonResult sendLoginCode(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom) {
LOGGER.info("快速登陆-发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom);
return sendVerificationCode2(phoneNo);
}
/**
* 快速注册发送验证码
*
* @param phoneNo
* @param registerFrom
* @return
*/
@CaptchaValidator
@RequestMapping("/send_regist_code")
public JsonResult sendRegistCode(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom) {
LOGGER.info("快速注册-发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom);
return sendVerificationCode2(phoneNo);
}
/**
* 绑卡成功发送短信
*
* @param phoneNo
* @return
*/
@RequestMapping("/send_bind_card_code")
public JsonResult sendBindCardCode(@RequestParam String phoneNo) {
LOGGER.info("绑卡成功-发送短信, phoneNo:{}", phoneNo);
String content = Constants.Sms.BINDCARD_SMS;
// return sendBindCardSms(phoneNo);
return sendBindCardSms(phoneNo, content);
}
/**
* 还款成功发送短信
*
* @param phoneNo
* @return
*/
@RequestMapping("/send_repay_code")
public JsonResult sendRepayCode(@RequestParam String phoneNo) {
LOGGER.info("还款成功-发送短信, phoneNo:{}", phoneNo);
String content = Constants.Sms.REPAY_SMS;
// return sendRepaySms(phoneNo);
return sendBindCardSms(phoneNo, content);
}
/**
* 发送验证码
*
* @param phoneNo
* @return
*/
private JsonResult sendVerificationCode(String phoneNo) {
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
return JsonResult.buildErrorStateResult("手机号必须为11位数字", null);
}
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES);
if (expire >= EXPIRE_MINUTES - 1) {
return JsonResult.buildSuccessResult("发送成功", null);
}
String randomCode = smsIsDebug ? "000000" : String.valueOf(random.nextInt(899999) + 100000);
String content = String.format(Constants.Sms.VERIFICATION_CODE, randomCode);
SmsResult smsResult = smsService.send(phoneNo, content);
if (smsResult.isRet()) {
redisTemplate.opsForValue().set(key, randomCode, EXPIRE_MINUTES, TimeUnit.MINUTES);
return JsonResult.buildSuccessResult("发送成功", null);
}
return JsonResult.buildErrorStateResult("发送失败", null);
}
private JsonResult sendVerificationCode2(String phoneNo) {
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
return JsonResult.buildErrorStateResult("手机号格式有误", null);
}
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES);
if (expire >= EXPIRE_MINUTES - 1) {
return JsonResult.buildSuccessResult("发送成功", null);
}
String randomCode = smsIsDebug ? "000000" : String.valueOf(random.nextInt(899999) + 100000);
String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", "");
List<String> newList = new ArrayList<>();
newList.add(randomCode);
ConfirmableMsg confirmableMsg = new ConfirmableMsg(
uniqueId, newList, "1", "1", phoneNo
);
try {
smsService.getSmsSender().sendConfirmableMessage(confirmableMsg);
redisTemplate.opsForValue().set(key, uniqueId + ":" + randomCode, EXPIRE_MINUTES, TimeUnit.MINUTES);
return JsonResult.buildSuccessResult("发送成功", uniqueId);
} catch (Exception e) {
LOGGER.error("发送短信验证码失败");
return JsonResult.buildErrorStateResult("发送失败", null);
}
}
private JsonResult sendBindCardSms(String phoneNo, String content) {
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
return JsonResult.buildErrorStateResult("手机号必须为11位数字", null);
}
SmsResult smsResult = smsService.send(phoneNo, content);
if (smsResult != null && smsResult.isRet()) {
return JsonResult.buildSuccessResult("发送成功", null);
}
return JsonResult.buildErrorStateResult("发送失败", null);
}
/**
* 发送固定短信文案
*
* @param phoneNo
* @return
*/
private JsonResult sendBindCardSms(String phoneNo) {
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
return JsonResult.buildErrorStateResult("手机号必须为11位数字", null);
}
try {
smsService.getSmsSender().sendAndForget(new SendAndForgetMsg(Collections.EMPTY_LIST, "2", "1", phoneNo));
} catch (Exception e) {
LOGGER.error("发送绑卡短信失败");
}
return JsonResult.buildSuccessResult(null, null);
}
private JsonResult sendRepaySms(String phoneNo) {
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
return JsonResult.buildErrorStateResult("手机号必须为11位数字", null);
}
try {
smsService.getSmsSender().sendAndForget(new SendAndForgetMsg(Collections.EMPTY_LIST, "3", "1", phoneNo));
} catch (Exception e) {
LOGGER.error("发送还款短信失败");
}
return JsonResult.buildSuccessResult(null, null);
}
}
package cn.quantgroup.xyqb.entity;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Created by Miraculous on 15/7/21.
*/
@Entity
@Table(name = "bank_card", uniqueConstraints = @UniqueConstraint(columnNames = "card_no"))
public class BankCard implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@NotNull
@Column(name = "card_no")
private String cardNo;
// 持卡人
@Column(name = "card_holder_name")
private String cardHolderName;
@Column(name = "phone_no")
private String phoneNo;
@Column(name = "bank_name")
private String bankName;
// 支行行号
@Column(name = "branch_no")
private String branchNo;
@Column(name = "branch_name")
private String branchName;
@Column(name = "has_already_binded")
private Boolean hasAlreadyBinded;
@Column(name = "city")
private String city;
@Column(name = "province")
private String province;
@Column(name = "created_at")
private Timestamp createdAt;
@Column(name = "updated_at")
private Timestamp updatedAt;
public BankCard() {
}
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
public String getBranchNo() {
return branchNo;
}
public void setBranchNo(String branchNo) {
this.branchNo = branchNo;
}
public String getCardHolderName() {
return cardHolderName;
}
public void setCardHolderName(String cardHolderName) {
this.cardHolderName = cardHolderName;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public Timestamp getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Timestamp createdAt) {
this.createdAt = createdAt;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public Timestamp getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Timestamp updatedAt) {
this.updatedAt = updatedAt;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Boolean getHasAlreadyBinded() {
return hasAlreadyBinded;
}
public void setHasAlreadyBinded(Boolean hasAlreadyBinded) {
this.hasAlreadyBinded = hasAlreadyBinded;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
@Override
public String toString() {
return "BankCard{" +
"bankName='" + bankName + '\'' +
", id=" + id +
", userId=" + userId +
", cardNo='" + cardNo + '\'' +
", cardHolderName='" + cardHolderName + '\'' +
", phoneNo='" + phoneNo + '\'' +
", branchNo='" + branchNo + '\'' +
", branchName='" + branchName + '\'' +
", hasAlreadyBinded=" + hasAlreadyBinded +
", city='" + city + '\'' +
", province='" + province + '\'' +
", createdAt=" + createdAt +
", updatedAt=" + updatedAt +
'}';
}
}
package cn.quantgroup.xyqb.entity;
import javax.persistence.*;
import java.io.Serializable;
/**
* Created by FrankChow on 15/7/8.
*/
@Entity
@Table(name = "channel", uniqueConstraints = @UniqueConstraint(columnNames = "channel_code"))
public class Channel implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//渠道代号
@Column(name = "channel_code")
private String channelCode;
//渠道名称
@Column(name = "name")
private String name;
@Column(name = "strategy_name")
private String strategyName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getChannelCode() {
return channelCode;
}
public void setChannelCode(String channelCode) {
this.channelCode = channelCode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStrategyName() {
return strategyName;
}
public void setStrategyName(String strategyName) {
this.strategyName = strategyName;
}
@Override
public String toString() {
return "Channel{" +
"channelCode='" + channelCode + '\'' +
", id=" + id +
", name='" + name + '\'' +
", strategyName='" + strategyName + '\'' +
'}';
}
}
package cn.quantgroup.xyqb.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author mengfan.feng
* @time 2015-10-27 15:13
*/
@Entity
@Table(name = "configuration")
@Getter
@Setter
@ToString
public class Configuration implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "k")
private String key;
@Column(name = "v")
private String value;
}
package cn.quantgroup.xyqb.entity;
import javax.persistence.*;
import java.sql.Timestamp;
/**
* Created by FrankChow on 15/11/4.
*/
@Entity
@Table(name = "ip_addr", uniqueConstraints = @UniqueConstraint(columnNames = "phone_no"))
public class IpAddr {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "phone_no")
private String phoneNo;
//第一次用户来源 channel_id
@Column(name = "registered_from")
private Long registeredFrom;
@Column(name = "ip_addr")
private String ipAddr;
@Column(name = "location")
private String location;
@Column(name = "location_id")
private int locationId;
@Column(name = "is_processed")
private Boolean isProcessed = false;
//创建时间
@Column(name = "created_at")
private Timestamp createdAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public int getLocationId() {
return locationId;
}
public void setLocationId(int locationId) {
this.locationId = locationId;
}
public Boolean getIsProcessed() {
return isProcessed;
}
public void setIsProcessed(Boolean isProcessed) {
this.isProcessed = isProcessed;
}
public Timestamp getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Timestamp createdAt) {
this.createdAt = createdAt;
}
public Long getRegisteredFrom() {
return registeredFrom;
}
public void setRegisteredFrom(Long registeredFrom) {
this.registeredFrom = registeredFrom;
}
}
package cn.quantgroup.xyqb.entity;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Created by Miraculous on 15/7/4.
*/
@Entity
@Table(name = "user", uniqueConstraints = @UniqueConstraint(columnNames = "phone_no"))
public class User implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//手机号
@Column(name = "phone_no")
private String phoneNo;
//uuid
@Column(name = "password")
private String password;
//第一次用户来源 channel_id
@Column(name = "registered_from")
private Long registeredFrom;
//uuid
@Column(name = "uuid")
private String uuid;
@Column(name = "enable")
private Boolean enable;
//创建时间
@Column(name = "created_at")
private Timestamp createdAt;
//上一次修改时间
@Column(name = "updated_at")
private Timestamp updatedAt;
public Boolean isEnable() {
return enable;
}
public void setEnable(Boolean enable) {
this.enable = enable;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getRegisteredFrom() {
return registeredFrom;
}
public void setRegisteredFrom(Long registeredFrom) {
this.registeredFrom = registeredFrom;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public Timestamp getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Timestamp createdAt) {
this.createdAt = createdAt;
}
public Timestamp getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Timestamp updatedAt) {
this.updatedAt = updatedAt;
}
}
package cn.quantgroup.xyqb.entity;
import cn.quantgroup.xyqb.model.Gender;
import cn.quantgroup.xyqb.model.IdType;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Created by FrankChow on 15/7/8.
*/
@Entity
@Table(name = "user_detail", uniqueConstraints = @UniqueConstraint(columnNames = "user_id"))
public class UserDetail implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "phone_no")
private String phoneNo;
@Column(name = "name")
private String name;
//证件号
@Column(name = "id_no")
private String idNo;
//0 身份证 1 军官证 2 护照
@Column(name = "id_type")
private IdType idType;
//身份证验真 0 未认证 1认证
@Column(name = "is_authenticated")
private Boolean isAuthenticated = false;
//0 未知 1 女 2 男
@Column(name = "gender")
private Gender gender;
@Column(name = "email")
private String email;
@Column(name = "qq")
private String qq;
//创建时间
@Column(name = "created_at")
private Timestamp createdAt;
//上一次修改时间
@Column(name = "updated_at")
private Timestamp updatedAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdNo() {
return idNo;
}
public void setIdNo(String idNo) {
this.idNo = idNo;
}
public IdType getIdType() {
return idType;
}
public void setIdType(IdType idType) {
this.idType = idType;
}
public Boolean getIsAuthenticated() {
return isAuthenticated;
}
public void setIsAuthenticated(Boolean isAuthenticated) {
this.isAuthenticated = isAuthenticated;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
public Timestamp getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Timestamp createdAt) {
this.createdAt = createdAt;
}
public Timestamp getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Timestamp updatedAt) {
this.updatedAt = updatedAt;
}
@Override
public String toString() {
return "UserDetail{" +
"createdAt=" + createdAt +
", id=" + id +
", userId=" + userId +
", phoneNo='" + phoneNo + '\'' +
", name='" + name + '\'' +
", idNo='" + idNo + '\'' +
", idType=" + idType +
", isAuthenticated=" + isAuthenticated +
", gender=" + gender +
", email='" + email + '\'' +
", qq='" + qq + '\'' +
", updatedAt=" + updatedAt +
'}';
}
}
package cn.quantgroup.xyqb.entity;
import cn.quantgroup.xyqb.model.Gender;
import cn.quantgroup.xyqb.model.IdType;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import java.io.Serializable;
/**
* Created by 11 on 2016/12/20.
*/
@Data
public class UserDetailRet implements Serializable{
private static final long serialVersionUID = -1L;
private Long id;
private Long userId;
private String phoneNo;
private String name;
//证件号
private String idNo;
//0 身份证 1 军官证 2 护照
private IdType idType;
//身份证验真 0 未认证 1认证
private Boolean isAuthenticated = false;
//0 未知 1 女 2 男
private Gender gender;
private String email;
private String qq;
//创建时间
private Long createdAt;
//上一次修改时间
private Long updatedAt;
/**
* 转换时间从timestamp到long
* @param userDetail
* @return return self
*/
public static UserDetailRet getUserDetail(UserDetail userDetail){
long createTimeStamp = userDetail.getCreatedAt().getTime();
long updateTimeStamp = userDetail.getUpdatedAt().getTime();
UserDetailRet userDetailRet = new UserDetailRet();
userDetailRet.setId(userDetail.getId());
userDetailRet.setName(userDetail.getName());
userDetailRet.setIdNo(userDetail.getIdNo());
userDetailRet.setPhoneNo(userDetail.getPhoneNo());
userDetailRet.setEmail(StringUtils.defaultIfEmpty(userDetail.getEmail(), ""));
userDetailRet.setGender(userDetail.getGender());
userDetailRet.setIdType(userDetail.getIdType());
userDetailRet.setIsAuthenticated(userDetail.getIsAuthenticated());
userDetailRet.setQq(StringUtils.defaultIfEmpty(userDetail.getQq(), ""));
userDetailRet.setUserId(userDetail.getUserId());
userDetailRet.setCreatedAt(createTimeStamp);
userDetailRet.setUpdatedAt(updateTimeStamp);
return userDetailRet;
}
}
package cn.quantgroup.xyqb.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author mengfan.feng
* @time 2015-09-10 15:32
*/
@Entity
@Table(name = "user_jr58", uniqueConstraints = @UniqueConstraint(columnNames = "user_id"))
@Getter
@Setter
@ToString
public class UserJr58 implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "wb_id")
private String wbId;
@Column(name = "wb_user_name")
private String wbUserName;
@Column(name = "customer_id")
private String customerId;
@Column(name = "name")
private String name;
@Column(name = "id_card")
private String idcard;
@Column(name = "email")
private String email;
@Column(name = "phone")
private String phone;
@Column(name = "info")
private String info;
@Column(name = "role_id")
private String roleId;
@Column(name = "flag")
private String flag;
@Column(name = "city")
private String city;
@Column(name = "access_mode")
private String accessMode;
@Column(name = "app_id")
private String appId;
@Column(name = "created_at")
private Timestamp createdAt;
@Column(name = "updated_at")
private Timestamp updatedAt;
@Column(name = "edu")
private String edu;
@Column(name = "income")
private String income;
@Column(name = "marry")
private String marry;
}
package cn.quantgroup.xyqb.entity;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Created by 11 on 2016/12/20.
*/
@Data
public class UserRet implements Serializable{
private static final long serialVersionUID = -1L;
private Long id;
//手机号
private String phoneNo;
//uuid
private String password;
//第一次用户来源 channel_id
private Long registeredFrom;
//uuid
private String uuid;
private Boolean enable;
//创建时间
private Long createdAt;
//上一次修改时间
private Long updatedAt;
public static UserRet getUserRet(User user){
Long createTimeStamp = user.getCreatedAt().getTime();
Long updateTimeStamp = user.getUpdatedAt().getTime();
UserRet userRet = new UserRet();
userRet.setId(user.getId());
userRet.setPhoneNo(user.getPhoneNo());
userRet.setEnable(true);
userRet.setPassword(StringUtils.defaultIfEmpty(user.getPassword(), ""));
userRet.setRegisteredFrom(user.getRegisteredFrom());
userRet.setUuid(user.getUuid());
userRet.setCreatedAt(createTimeStamp);
userRet.setUpdatedAt(updateTimeStamp);
return userRet;
}
}
package cn.quantgroup.xyqb.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.io.Serializable;
/**
* Created by Miraculous on 15/10/29.
*/
@Entity
@Table(name = "uuid_phone_mapping", uniqueConstraints = @UniqueConstraint(columnNames = "uuid"))
@Getter
@Setter
@ToString
public class UuidPhoneMapping implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column (name = "uuid")
private String uuid;
@Column (name = "phone_no")
private String phoneNo;
}
package cn.quantgroup.xyqb.event;
import lombok.Getter;
import lombok.ToString;
import org.springframework.context.ApplicationEvent;
/**
* @author mengfan.feng
* @time 2015-09-15 15:05
*/
@Getter
@ToString
public class UserinfoChangedEvent extends ApplicationEvent {
private final String uuid;
private final Long channelId;
public UserinfoChangedEvent(Object source, String uuid, Long channelId) {
super(source);
this.uuid = uuid;
this.channelId = channelId;
}
}
package cn.quantgroup.xyqb.event.jr58;
import cn.quantgroup.xyqb.service.http.IHttpService;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class Jr58DataSender {
private static final Logger LOGGER = LoggerFactory.getLogger(Jr58DataSender.class);
@Autowired
private Jr58MessageSigner jr58MessageSigner;
@Autowired
private IHttpService httpService;
@Value("${jr58.notify.userinfo}")
private String jr58nNotifyUserinfo;
/**
* 向58金融同步用户信息
*
* @param uuid
*/
@Async
public void sendUserinfo(String uuid) {
try {
JsonObject json = new JsonObject();
json.addProperty("salaryWay", 0);
json.addProperty("loanPurpose", "12");
json.addProperty("job", 0);
json.addProperty("account", 1000);
json.addProperty("salary", 0);
json.addProperty("hourse", 1);
json.addProperty("isShebao", 0);
json.addProperty("education", "");
json.addProperty("isCreditCard", "0");
json.addProperty("isOtherLoanOrg", "0");
String userinfo = json.toString();
String param = uuid + "|1|" + userinfo;
String sign = jr58MessageSigner.sign(param);
Map<String, String> parameters = ImmutableMap.<String, String>builder()
.put("customerId", uuid)
.put("authorState", "100")
.put("baseFlag", "1")
.put("userinfo", userinfo)
.put("sign", sign)
.build();
httpService.post(jr58nNotifyUserinfo, parameters);
} catch (Exception e) {
LOGGER.error("向58金融同步用户信息", e);
}
}
}
package cn.quantgroup.xyqb.event.jr58;
import cn.quantgroup.cloudconfig.SafeValue;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
@Service
public class Jr58MessageSigner {
private PrivateKey generatedSigningKey;
@SafeValue("jr58.sign.key")
private String signingKeySpec;
@PostConstruct
private void init() throws Exception {
if (StringUtils.isEmpty(signingKeySpec)) return;
byte[] keyBytes = Base64.getDecoder().decode(signingKeySpec);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
generatedSigningKey = keyFactory.generatePrivate(pkcs8KeySpec);
}
public String sign(String s) throws Exception {
if (generatedSigningKey == null) return "";
byte[] data = s.getBytes();
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(generatedSigningKey);
signature.update(data);
byte[] signedBytes = signature.sign();
return Base64.getEncoder().encodeToString(signedBytes);
}
}
package cn.quantgroup.xyqb.event.jr58;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.event.UserinfoChangedEvent;
import cn.quantgroup.xyqb.service.user.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;
@Service
public class Jr58Notifier implements ApplicationListener<UserinfoChangedEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(Jr58Notifier.class);
@Autowired
private Jr58DataSender jr58DataSender;
@Autowired
private IUserService userService;
@Override
public void onApplicationEvent(UserinfoChangedEvent event) {
LOGGER.info("向58金融同步信息, event:{}", event);
String uuid = event.getUuid();
Long channelId = event.getChannelId();
if (StringUtils.isEmpty(uuid) || channelId == null || channelId != Constants.Channel.JR58) {
return;
}
User user = userService.findByUuid(uuid);
if (user == null || user.getRegisteredFrom() != Constants.Channel.JR58) {
return;
}
jr58DataSender.sendUserinfo(uuid);
}
}
package cn.quantgroup.xyqb.exception;
/**
* Created by Miraculous on 15/7/11.
*/
public class IdCardException extends RuntimeException {
public IdCardException() {
super("非法的身份证号码");
}
public IdCardException(String message) {
super(message);
}
}
package cn.quantgroup.xyqb.exception;
/**
* Created by Miraculous on 15/7/12.
*/
public class NullUserException extends RuntimeException {
public NullUserException() {
super("未找到用户");
}
public NullUserException(String message) {
super(message);
}
}
package cn.quantgroup.xyqb.exception;
import org.springframework.security.core.AuthenticationException;
/**
* @author mengfan.feng
* @time 2015-09-08 17:49
*/
public class PasswordErrorException extends AuthenticationException {
public PasswordErrorException(String msg, Throwable t) {
super(msg, t);
}
public PasswordErrorException(String msg) {
super(msg);
}
}
package cn.quantgroup.xyqb.exception;
/**
* @author mengfan.feng
* @time 2015-11-16 11:10
* @see cn.quantgroup.xyqb.model.JsonResult#msg
*/
public class ResponseException extends RuntimeException {
public ResponseException(String message) {
super(message);
}
public ResponseException(String message, Throwable cause) {
super(message, cause);
}
}
package cn.quantgroup.xyqb.exception;
/**
* Created by Miraculous on 15/7/29.
*/
public class ResubmissionException extends RuntimeException {
public ResubmissionException() {
super("不能重复提交表单");
}
}
package cn.quantgroup.xyqb.exception;
import org.springframework.security.core.AuthenticationException;
/**
* @author mengfan.feng
* @time 2015-09-08 17:43
*/
public class UserNotExistException extends AuthenticationException {
public UserNotExistException(String msg, Throwable t) {
super(msg, t);
}
public UserNotExistException(String msg) {
super(msg);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment