a8fd3dbf252fb402f2f0e37cc02e361bbc265ea7.svn-base 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. package com.iamberry.app.api.controller;
  2. import java.awt.Color;
  3. import java.awt.image.BufferedImage;
  4. import java.io.File;
  5. import java.io.IOException;
  6. import java.io.OutputStream;
  7. import java.util.Date;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import java.util.regex.Matcher;
  11. import java.util.regex.Pattern;
  12. import javax.imageio.ImageIO;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15. import org.apache.commons.lang3.StringUtils;
  16. import org.slf4j.Logger;
  17. import org.slf4j.LoggerFactory;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.stereotype.Controller;
  20. import org.springframework.web.bind.WebDataBinder;
  21. import org.springframework.web.bind.annotation.InitBinder;
  22. import org.springframework.web.bind.annotation.RequestMapping;
  23. import org.springframework.web.bind.annotation.RequestMethod;
  24. import org.springframework.web.bind.annotation.RequestParam;
  25. import org.springframework.web.bind.annotation.ResponseBody;
  26. import com.fasterxml.jackson.databind.ObjectMapper;
  27. import com.iamberry.app.api.util.AppVersion;
  28. import com.iamberry.app.api.util.TokenUtil;
  29. import com.iamberry.app.api.util.Utility;
  30. import com.iamberry.app.api.util.VerifyCodeUtil;
  31. import com.iamberry.app.config.Constants;
  32. import com.iamberry.app.config.Response;
  33. import com.iamberry.app.config.ResponseHeader;
  34. import com.iamberry.app.core.dto.RemoteIpInfoDTO;
  35. import com.iamberry.app.core.dto.UserDTO;
  36. import com.iamberry.app.core.entity.User;
  37. import com.iamberry.app.tool.util.AES;
  38. import com.iamberry.app.tool.util.HttpUtility;
  39. import com.iamberry.app.tool.util.MD5;
  40. import com.iamberry.cache.LocalCache;
  41. import com.iamberry.wechat.tools.ResponseJson;
  42. import sun.misc.BASE64Decoder;
  43. /**
  44. * UserController
  45. *
  46. * @author Moon Cheng
  47. * @date 2016年1月18日 上午11:53:04
  48. */
  49. @Controller
  50. @RequestMapping("/secure/user")
  51. public class UserController extends BaseController {
  52. @Autowired
  53. HttpServletResponse response;
  54. /**
  55. * 日志
  56. */
  57. private Logger logger = LoggerFactory.getLogger(UserController.class);
  58. /**
  59. * 验证码的缓存, 如果存在负载均衡,如此的实现,存在问题,可能导致验证失败( put ----> S1, check ------> S2)
  60. */
  61. public LocalCache<String, String> verifyCodeCache = new LocalCache<String, String>(100);
  62. /**
  63. * 保存用户头像的路径
  64. */
  65. private String saveRootPath = "/common/user_head/";
  66. /**
  67. * Base64 工具类
  68. */
  69. private BASE64Decoder decoder = new BASE64Decoder();
  70. /**
  71. * 主域名
  72. */
  73. private String domain = "http://app.iamberry.com";
  74. @InitBinder("user")
  75. public void initBinderUser(WebDataBinder binder) {
  76. binder.setFieldDefaultPrefix("user.");
  77. }
  78. /**
  79. * 用户手机注册,成功返回json格式的用户信息
  80. * @author Moon Cheng
  81. * @param phone 手机号码
  82. * @param verificationCode 手机收到的短信验证码
  83. * @param password 密码
  84. * @return 2101:验证码错误;2102:验证码超时;1000:请求成功;2000:注册失败;
  85. */
  86. @RequestMapping(value = "/register", method = RequestMethod.POST)
  87. @ResponseBody
  88. private Response register(
  89. @RequestParam("phone") String phone,
  90. @RequestParam("verification_code") String verificationCode,
  91. @RequestParam("password") String password,
  92. HttpServletRequest request) {
  93. // 校验验证码
  94. int status = checkVerifyCode(phone, verificationCode, 1); //验证手机验证码是否正确
  95. if (status == -1) {
  96. //验证码错误
  97. return Response.ERROR_CODE;
  98. } else if (status == -2) {
  99. //验证码超时
  100. return Response.CODE_TIMEOUT;
  101. } else if (status != 1) {
  102. // 状态错误
  103. return Response.FAILURE;
  104. }
  105. // 验证成功, 并开始注册
  106. User user = new User();
  107. String ip = Utility.getIp(request);
  108. user = userService.register(phone, password, ip);
  109. if (user == null) {
  110. //注册失败
  111. return Response.FAILURE;
  112. }
  113. // 解析App版本
  114. AppVersion v = AppVersion.parseUserAgent(request.getHeader("User-Agent") == null ? "" : request.getHeader("User-Agent"));
  115. if (v.getVersion() < 125) {
  116. // 兼容低版本APP,因为低版本的APP是自己注册的
  117. UserDTO userInfo = new UserDTO(user.getId(), user.getUsername(), user.getPassword(), user.getToken(), user.getDisplay_name(),
  118. user.getDisplay_picture(), user.getCreated_on(), user.getExt_open_id(), user.getExt_name(), user.getExt_type(),
  119. user.getLocation(), user.getBaby_nickname(), user.getBaby_dob(), user.getBaby_gender(), user.getStatus_());
  120. userInfo.setEncryptUsername(AES.encrypt(user.getUsername()));
  121. userInfo.setUserCode(Constants.TUYA_DEFAULT_PASS);
  122. return Response.SUCCESS.setData(userInfo, 1);
  123. }
  124. // 注册涂鸦,当前用户需要完善宝宝信息
  125. UserDTO userDTO = userService.tuyaConnect(user);
  126. userDTO.setIs_perfect_user(2);
  127. return Response.SUCCESS.setData(userDTO, 1);
  128. }
  129. /**
  130. * 第三方【微信】用户手机绑定,
  131. * @author Moon Cheng
  132. * @param phone 手机号
  133. * @param openId 微信的openid
  134. * @return 1000:请求成功;2000:注册失败;
  135. */
  136. @RequestMapping(value = "/third_part_binding_phone", method = RequestMethod.POST)
  137. @ResponseBody
  138. private Response thirdPartBindingPhone(
  139. @RequestParam("phone") String phone,
  140. @RequestParam("open_id") String openId,
  141. @RequestParam(value = "code", required = false) String code) {
  142. // 兼容低版本APP
  143. if (code != null) {
  144. ResponseJson json = codeService.validCode(phone, code, 3);
  145. if (json.getReturnCode() != 200) {
  146. return Response.FAILURE.setData(json);
  147. }
  148. }
  149. // 执行绑定
  150. User user = userService.thirdPartBindingPhone(phone, openId);
  151. if (user == null) {
  152. return Response.USER_NOT_EXIST;
  153. }
  154. // 注册涂鸦,并且判断用户当前的状态
  155. UserDTO dto = userService.tuyaConnect(user);
  156. // 返回状态填充
  157. if (Constants.USER_NOW_INIT.equals(user.getStatus_())) {
  158. // 需要完善手机号码
  159. dto.setIs_perfect_user(1);
  160. } else if (Constants.USER_SAVE_TEL.equals(user.getStatus_())) {
  161. // 需要完善宝宝信息
  162. dto.setIs_perfect_user(2);
  163. } else {
  164. // 注册完成
  165. dto.setIs_perfect_user(3);
  166. }
  167. return Response.SUCCESS.setData(dto, 1);
  168. }
  169. /**
  170. * login
  171. * 手机号登录,
  172. * @param phone 手机号
  173. * @param password 密码
  174. * @return 2012:身份验证失败;2013:账户冻结;1000:请求成功;
  175. */
  176. @RequestMapping(value = "/login", method = RequestMethod.POST)
  177. @ResponseBody
  178. private Response login(
  179. @RequestParam(value = "phone", required = true) String phone,
  180. @RequestParam(value = "password", required = true) String password) {
  181. // 登录
  182. Object user = userService.login(phone, password);
  183. int status = 0;
  184. if (user instanceof Integer) {
  185. status = (Integer) user;
  186. switch (status) {
  187. case -1: //账号不存在
  188. return Response.USER_NOT_EXIST;
  189. case -2: //密码错误
  190. return Response.AUTHENTICATION_ERROR;
  191. case -3: //用户状态不正常
  192. return Response.USER_FROZEN_ERROR;
  193. }
  194. }
  195. return Response.SUCCESS.setData((UserDTO) user, 1);
  196. }
  197. /**
  198. * thirdPartLogin
  199. * 第三方登录
  200. * @param openId 微信open_id
  201. * @param extType 来源 qq或者微信
  202. * @param extName extname
  203. * @param extPicture 图片
  204. * @return 2012:身份验证失败;2013:账户冻结;1000:请求成功;
  205. */
  206. @RequestMapping(value = "/third_part_login", method = RequestMethod.POST)
  207. @ResponseBody
  208. private Response thirdPartLogin(
  209. @RequestParam(value = "open_id") String openId,
  210. @RequestParam(value = "ext_type") String extType,
  211. @RequestParam(value = "ext_name") String extName,
  212. @RequestParam(value = "ext_picture") String extPicture) {
  213. String ip = Utility.getIp(request);
  214. User user = userService.thirdPartLogin(openId, extType, extName, extPicture, ip);
  215. if (Constants.USER_INACTIVE.equals(user.getStatus_())) {
  216. return Response.USER_FROZEN_ERROR;
  217. }
  218. // 同步涂鸦
  219. UserDTO dto = userService.tuyaConnect(user);
  220. if (Constants.USER_NOW_INIT.equals(user.getStatus_())) {
  221. // 需要完善手机号码
  222. dto.setIs_perfect_user(1);
  223. } else if (Constants.USER_SAVE_TEL.equals(user.getStatus_())) {
  224. // 需要完善宝宝信息
  225. dto.setIs_perfect_user(2);
  226. } else {
  227. // 注册完成
  228. dto.setIs_perfect_user(3);
  229. }
  230. return Response.SUCCESS.setData(dto, 1);
  231. }
  232. /**
  233. * getUserInfo
  234. * 获取用户基本信息
  235. * @param id 用户id
  236. * @token 用户token 登录的时候设置的唯一的token
  237. * @return Response 2100:无效token;2020:无效用户;1000:请求成功;
  238. */
  239. @RequestMapping(value = "/get_user_info", method = RequestMethod.POST)
  240. @ResponseBody
  241. private Response getUserInfo(@RequestParam("token") String token) {
  242. User userInfo = userService.validateUserToken(token);
  243. if (userInfo == null) {//token不存在,表示登录的时候没有..
  244. return Response.INVALID_TOKEN;
  245. }
  246. if (Constants.USER_NOW_INIT.equals(userInfo.getStatus_())) {
  247. // 需要完善手机号码
  248. userInfo.setIs_perfect_user(1);
  249. } else if (Constants.USER_SAVE_TEL.equals(userInfo.getStatus_())) {
  250. // 需要完善宝宝信息
  251. userInfo.setIs_perfect_user(2);
  252. } else {
  253. // 注册完成
  254. userInfo.setIs_perfect_user(3);
  255. }
  256. // 兼容低版本APP
  257. if (userInfo.getLocation() == null) {
  258. userInfo.setLocation("深圳");
  259. }
  260. return Response.SUCCESS.setData(userInfo, 1);
  261. }
  262. protected static final ObjectMapper mapper = new ObjectMapper();
  263. /**
  264. * getLocation
  265. *
  266. * @param ip
  267. * @return String
  268. */
  269. public RemoteIpInfoDTO getLocation(String ip) {
  270. RemoteIpInfoDTO remoteIpInfoDTO = new RemoteIpInfoDTO();
  271. if (ip.indexOf(",") != -1) {
  272. ip = ip.split(",")[0];
  273. }
  274. logger.info("IP为:" + ip);
  275. try {
  276. String result = HttpUtility.httpsGet("http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=" + ip);
  277. remoteIpInfoDTO = mapper.readValue(result, RemoteIpInfoDTO.class);
  278. } catch (Exception e) {
  279. }
  280. return remoteIpInfoDTO;
  281. }
  282. /**
  283. * updateProfile
  284. * 更新用户基本信息
  285. * @param user 用户信息
  286. * @param token token
  287. * @return Response 2100:无效token;1000:请求成功;
  288. */
  289. @RequestMapping(value = "/update_profile", method = RequestMethod.POST)
  290. @ResponseBody
  291. private Response updateProfile(
  292. User user,
  293. @RequestParam("token") String token,
  294. HttpServletRequest request) {
  295. User userInfo = userService.updateUserInfo(user, token);
  296. if (userInfo == null) {
  297. return Response.INVALID_TOKEN;
  298. }
  299. /**
  300. * 完善成功
  301. */
  302. userInfo.setIs_perfect_user(3);
  303. UserDTO dto = userService.tuyaConnect(userInfo);
  304. return Response.SUCCESS.setData(dto, 1);
  305. }
  306. /**
  307. * updateDisplayPicture
  308. * 更改用户头像,注意上传头像成功后,需要一段时间才能同步到所有服务器
  309. * @param user 用户信息
  310. * @param token 唯一标识符
  311. * @return Response
  312. * @throws IOException
  313. */
  314. @SuppressWarnings({ "deprecation"})
  315. @RequestMapping(value = "/update_display_picture", method = RequestMethod.POST)
  316. @ResponseBody
  317. private Response updateDisplayPicture(@RequestParam("picture_base64") String pictureBase64,
  318. @RequestParam("token") String token) throws IOException {
  319. // 判断文件类型
  320. byte [] b = new byte[28];
  321. pictureBase64.getBytes(0, 27, b, 0);
  322. String temp = new String(b);
  323. try {
  324. b = decoder.decodeBuffer(temp);
  325. } catch (IOException e) {
  326. logger.error("updateDisplayPicture:" + e.getMessage());
  327. return Response.FAILURE;
  328. }
  329. // 获取上传的文件类型
  330. String type = null;
  331. // 文件头
  332. String fileHead = com.iamberry.wechat.file.FileUtils.byte2hex(b);
  333. fileHead = fileHead.toUpperCase();
  334. type = com.iamberry.wechat.file.FileUtils.getType(fileHead);
  335. if (type == null) {
  336. return Response.FAILURE;
  337. }
  338. // 获取保存地址
  339. String savePath = request.getServletContext().getRealPath(saveRootPath);
  340. StringBuilder tempDir = new StringBuilder(savePath);
  341. Long ran = new Date().getTime();
  342. tempDir.append(File.separator);
  343. tempDir.append(ran);
  344. tempDir.append(File.separator);
  345. // 判断保存路径是否存在,如果不存在,那么创建
  346. File file=new File(savePath);
  347. if (!file.exists()) {
  348. logger.info("updateDisplayPicture-exists");
  349. file.mkdirs();
  350. }
  351. // 获取保存文件名称
  352. StringBuilder saveName = new StringBuilder(com.iamberry.wechat.file.FileUtils.getToken());
  353. saveName.append(".").append(type);
  354. tempDir.append(saveName);
  355. // 保存磁盘
  356. String userHeadURL = null;
  357. if (!com.iamberry.wechat.file.FileUtils.generateImage(pictureBase64, tempDir.toString())) {
  358. logger.error("updateDisplayPicture-generateImage saveFile Error");
  359. return Response.FAILURE;
  360. } else {
  361. userHeadURL = domain + request.getContextPath() + saveRootPath + ran + "/" + saveName.toString();
  362. }
  363. // 保存
  364. String path = userService.updateDisplayPicture(userHeadURL, token);
  365. if (path.equals("ERROR")) {
  366. return Response.FAILURE;
  367. }
  368. return Response.SUCCESS.setData(userHeadURL, 1);
  369. }
  370. /**
  371. * 【外包开发的老版本】获取头像,外包是为了完成分布式的文件共享
  372. */
  373. @RequestMapping(value = "/avator/{id}/{rand}", method = RequestMethod.GET)
  374. @ResponseBody
  375. private void getDisplayPicture() {
  376. String url = request.getRequestURI();
  377. url = url.substring(0, url.lastIndexOf('/'));
  378. String userID = url.substring(url.lastIndexOf('/') + 1);
  379. String avator = userService.selectUserAvator(Long.valueOf(userID));
  380. response.setContentType("image/jpg");
  381. try {
  382. OutputStream os = response.getOutputStream();
  383. byte[] decoderBytes = decoder.decodeBuffer(avator);
  384. os.write(decoderBytes);
  385. os.flush();
  386. os.close();
  387. } catch (Exception e) {
  388. }
  389. }
  390. /**
  391. * changePassword
  392. * 修改手机密码
  393. * @param oldPassword 新密码
  394. * @param newPassword 旧密码
  395. * @param token token
  396. * @return Response 2101:验证码错误;2102:验证码超时;2100:无效token;1000:请求成功;
  397. */
  398. @RequestMapping(value = "/change_password", method = RequestMethod.POST)
  399. @ResponseBody
  400. private Response changePassword(
  401. @RequestParam("old_password") String oldPassword,
  402. @RequestParam("new_password") String newPassword,
  403. @RequestParam("token") String token) {
  404. int status = userService.changePassword(oldPassword, newPassword, token);
  405. if (status == -1) { //token错误
  406. return Response.INVALID_TOKEN;
  407. } else if (status == 0) { //密码错误
  408. return Response.ERROR_OLDPASSWORD;
  409. } else {
  410. return Response.SUCCESS.setData(null);
  411. }
  412. }
  413. /**
  414. * changePhone
  415. * 修改手机号码
  416. * @author Moon Cheng, Yin
  417. * @param newPhone 新手机号
  418. * @param token token
  419. * @param verificationCode 手机验证码
  420. * @return2101:验证码错误;2102:验证码超时;2100:无效token;1000:请求成功;
  421. */
  422. @RequestMapping(value = "/change_phone", method = RequestMethod.POST)
  423. @ResponseBody
  424. private Response changePhone(@RequestParam("new_phone") String newPhone,
  425. @RequestParam("verification_code") String verificationCode, @RequestParam("token") String token) {
  426. int status = checkVerifyCode(newPhone, verificationCode, 2);
  427. User user = null;
  428. if (status == -1) { //验证码错误
  429. return Response.ERROR_CODE;
  430. } else if (status == -2) { //验证码超时
  431. return Response.CODE_TIMEOUT;
  432. } else if (status == 1) {
  433. user = userService.changePhone(newPhone, token);
  434. if (user == null) {
  435. return Response.INVALID_TOKEN;
  436. }
  437. }
  438. return Response.SUCCESS.setData(userService.tuyaConnect(user), 1);
  439. }
  440. /**
  441. * resetPassword
  442. * 重置手机密码
  443. * @param username 用户米
  444. * @param newPassword 新密码
  445. * @param verificationCode 验证码
  446. * @return2101:验证码错误;2102:验证码超时;2001:无效用户;2000:重置密码失败; 1000:请求成功;
  447. */
  448. @RequestMapping(value = "/reset_password", method = RequestMethod.POST)
  449. @ResponseBody
  450. private Response resetPassword(
  451. @RequestParam(value = "username") String username,
  452. @RequestParam("new_password") String newPassword,
  453. @RequestParam("verification_code") String verificationCode) {
  454. int status = checkVerifyCode(username, verificationCode, 3);
  455. if (status == -1) {//验证码错误
  456. return Response.ERROR_CODE;
  457. } else if (status == -2) { //验证码超时
  458. return Response.CODE_TIMEOUT;
  459. } else if (status == 1) {
  460. status = userService.resetPassWord(username, newPassword);
  461. if (status == -3) {//账号不存在
  462. return Response.USER_NOT_EXIST;
  463. } else if (status == 0) {
  464. return Response.FAILURE;
  465. }
  466. }
  467. return Response.SUCCESS.setData(null);
  468. }
  469. /**
  470. * 获取token,用于发送验证码
  471. * @return
  472. * @author 献
  473. * @Time 2016年12月5日
  474. */
  475. @RequestMapping(value = "/get_token", method = RequestMethod.POST)
  476. @ResponseBody
  477. public Response getToken(@RequestParam("phone") String phone) {
  478. // 格式校验
  479. if (StringUtils.isEmpty(phone)) {
  480. return new Response(new ResponseHeader(404, "手机号码有误!", 0));
  481. }
  482. // 校验手机号码格式
  483. if (!isMobileNumber(phone)) {
  484. return new Response(new ResponseHeader(404, "手机号码有误!", 0));
  485. }
  486. // 防轰炸原则
  487. Response t = codeService.interval(phone);
  488. if (t.getHeader().getStatus() == 404) {
  489. // 接口限制,不能使用
  490. return t;
  491. }
  492. // 生成原始token
  493. String key = TokenUtil.getToken();
  494. if (key.length() < 16) {
  495. key = Utility.getRandomCode(16);
  496. }
  497. // 获取加密的key
  498. key = key.substring(0, 16);
  499. String temp = AES.encryptCBC(phone, key, "IAMBERRY321#$%^&");
  500. StringBuilder token = new StringBuilder(key);
  501. token.append(temp);
  502. // 返回token
  503. if (t.getHeader().getStatus() == 403) {
  504. // 1001 需要验证码 ** 1.2.6之前都没有此
  505. return new Response(new ResponseHeader(1000, "SUCCESS_TO_VERIFY", 0), token);
  506. } else {
  507. // 1000 成功
  508. return new Response(new ResponseHeader(1000, "SUCCESS", 0), token);
  509. }
  510. }
  511. /**
  512. * 获取验证码
  513. * @param response
  514. * @throws IOException
  515. * @author 献
  516. * @Time 2016年12月13日
  517. */
  518. @RequestMapping(value = "/get/image_code")
  519. public void geImagetVerifyCode(HttpServletResponse response,
  520. @RequestParam(value = "phone") String phone,
  521. @RequestParam(value = "token") String token,
  522. @RequestParam(value = "width", required = false, defaultValue = "130") Integer width,
  523. @RequestParam(value = "height", required = false, defaultValue = "30") Integer height
  524. ) throws IOException {
  525. // 格式校验
  526. /*User user = userService.validateUserToken(token);
  527. if (user == null) {
  528. // token无效
  529. response.getWriter().write("{\"status\":402}");
  530. return;
  531. }*/
  532. if (StringUtils.isEmpty(phone)) {
  533. // 手机号码不能为空
  534. response.getWriter().write("{\"status\":403}");
  535. return;
  536. }
  537. if (!isMobileNumber(phone)) {
  538. // 手机号码格式不正确
  539. response.getWriter().write("{\"status\":404}");
  540. return;
  541. }
  542. // 生成验证码,并保存
  543. String verifyCode = VerifyCodeUtil.generateTextCode(0, 4, null);
  544. response.setContentType("image/jpeg");
  545. BufferedImage bufferedImage = VerifyCodeUtil.generateImageCode(verifyCode, width, height, new java.util.Random().nextInt(5), true, Color.WHITE, Color.BLACK, null);
  546. ImageIO.write(bufferedImage, "JPEG", response.getOutputStream());
  547. // 保存验证码 K:phone,V:code
  548. verifyCodeCache.put(phone, verifyCode);
  549. }
  550. /**
  551. * 验证手机号格式
  552. * @param mobilenumber
  553. * @return boolean,true:校验通过;false:表示校验失败
  554. * @author 献
  555. * @Time 2016年12月6日
  556. */
  557. public static boolean isMobileNumber(String mobilenumber) {
  558. Pattern p = Pattern.compile("^[1][3,4,5,7,8][0-9]{9}$");
  559. Matcher m = p.matcher(mobilenumber);
  560. return m.matches();
  561. }
  562. /**
  563. * 发生手机验证码<br>
  564. * 1代表注册,2代表更换手机号,3代表忘记密码
  565. * @param phone 手机号码
  566. * @param statusCode 使用场景
  567. * @param token 验证码token
  568. * @param timestamp 时间戳
  569. * @param imageCode 图片验证码
  570. * @param signature 签名
  571. * @return
  572. * @author 献
  573. * @Time 2016年12月13日
  574. */
  575. @RequestMapping(value = "/send_code", method = RequestMethod.GET)
  576. @ResponseBody
  577. private Response sendCode(
  578. @RequestParam(value = "phone") String phone,
  579. @RequestParam("status_code") int statusCode,
  580. @RequestParam(value = "code_token", required = false) String token,
  581. @RequestParam(value = "timestamp", required = false) String timestamp,
  582. @RequestParam(value = "image_code", required = false) String imageCode,
  583. @RequestParam(value = "signature", required = false) String signature) {
  584. // 放轰炸原则 & 校验验证码
  585. Response t = codeService.interval(phone);
  586. if (t.getHeader().getStatus() == 404) {
  587. // 接口限制,不能使用
  588. return t;
  589. }
  590. // 版本控制
  591. AppVersion appVersion = (AppVersion) request.getAttribute("v");
  592. if (appVersion != null && appVersion.getVersion() >= 126 && t.getHeader().getStatus() == 403) {
  593. // app 1.2.6
  594. // 校验token & phone
  595. if (StringUtils.isEmpty(token) || token.length() <= 16) {
  596. return new Response(new ResponseHeader(404, "您的流程有误,或者请下载最新版本APP!", 0));
  597. }
  598. String key = token.substring(0, 16);
  599. String temp = AES.decryptCBC(token.substring(16), key, "IAMBERRY321#$%^&");
  600. // 校验签名
  601. StringBuilder builder = new StringBuilder("IAMBERRY321");
  602. builder.append(statusCode).append(token).append(timestamp);
  603. if (!MD5.md5(builder.toString()).equals(signature)) {
  604. return new Response(new ResponseHeader(404, "您的流程有误,或者请下载最新版本APP!", 0));
  605. }
  606. if (!phone.equals(temp)) {
  607. return new Response(new ResponseHeader(404, "您的流程有误,或者请下载最新版本APP!", 0));
  608. }
  609. // 置换数据
  610. phone = temp;
  611. // 需要验证码
  612. if (StringUtils.isEmpty(imageCode)) {
  613. return new Response(new ResponseHeader(403, "请输入图片验证码", 0));
  614. }
  615. if (!StringUtils.equals(imageCode, verifyCodeCache.get(phone))) {
  616. return new Response(new ResponseHeader(402, "图片验证码错误,请重新输入!", 0));
  617. }
  618. } else {
  619. // 1.2.6 以前的版本
  620. if (token != null) {
  621. // 1.2.5版本
  622. // 校验token & phone
  623. if (StringUtils.isEmpty(token) || token.length() <= 16) {
  624. return new Response(new ResponseHeader(404, "您的流程有误,或者请下载最新版本APP!", 0));
  625. }
  626. String key = token.substring(0, 16);
  627. String temp = AES.decryptCBC(token.substring(16), key, "IAMBERRY321#$%^&");
  628. // 校验签名
  629. StringBuilder builder = new StringBuilder("IAMBERRY321");
  630. builder.append(statusCode).append(token).append(timestamp);
  631. if (!MD5.md5(builder.toString()).equals(signature)) {
  632. return new Response(new ResponseHeader(404, "您的流程有误,或者请下载最新版本APP!", 0));
  633. }
  634. if (!phone.equals(temp)) {
  635. return new Response(new ResponseHeader(404, "您的流程有误,或者请下载最新版本APP!", 0));
  636. }
  637. // 置换数据
  638. phone = temp;
  639. }
  640. // 1.2.5以前的版本
  641. }
  642. // 通用的逻辑部分
  643. String code = null;
  644. Map<String, Integer> status = new HashMap<String, Integer>();
  645. User user = new User();
  646. try {
  647. switch (statusCode) {
  648. case 1:// register
  649. user = userService.selectUserByUsername(phone);
  650. if (user != null) {
  651. return Response.ERROR_REGISTER;
  652. }
  653. break;
  654. case 2:// change phone
  655. user = userService.selectUserByUsername(phone);
  656. if (user != null) {
  657. return Response.ERROR_REGISTER;
  658. }
  659. break;
  660. case 3:// reset password
  661. /*user = userService.selectUserByUsername(phone);
  662. if (user == null) {
  663. return Response.USER_NOT_EXIST;
  664. }*/
  665. break;
  666. default:
  667. break;
  668. }
  669. codeService.sendCode(phone, statusCode);
  670. status.put("code", 0);
  671. } catch (Exception e) {
  672. return Response.SERVER_INTERNAL_ERROR;
  673. }
  674. if (0 == status.get(Constants.SMS_RETURNCODE)) {
  675. return Response.SUCCESS.setData(code, 0);
  676. } else {
  677. return Response.FAILURE.setHeader(new ResponseHeader(status.get(Constants.SMS_RETURNCODE), "", 0));
  678. }
  679. }
  680. /**
  681. * 获取封面图片
  682. * @return json
  683. */
  684. @RequestMapping(value = "/start_page", method = RequestMethod.GET)
  685. @ResponseBody
  686. private Response getStartPage() {
  687. String pageUrl = userService.getStartPage();
  688. return Response.SUCCESS.setData(pageUrl, 1);
  689. }
  690. /**
  691. * 获取地址url
  692. * @return
  693. */
  694. @RequestMapping(value = "/get_location", method = RequestMethod.GET)
  695. @ResponseBody
  696. private Response getLocation(HttpServletRequest request) {
  697. String IP = Utility.getIp(request);
  698. RemoteIpInfoDTO remoteIpInfoDTO = userService.getLocation(IP);
  699. return Response.SUCCESS.setData(remoteIpInfoDTO, 1);
  700. }
  701. /**
  702. * 获取app版本号
  703. * @return
  704. */
  705. @RequestMapping(value = "/get_version", method = RequestMethod.GET)
  706. @ResponseBody
  707. private Response getApkVersion() {
  708. return Response.SUCCESS.setData(userService.getApkVersion());
  709. }
  710. }