business:
Database user with micro-channel public attention to the actual number of user data checking.
demand:
Click the button to the front [update the user concerned state], the back-end update data asynchronously start threads, and thread can check the results.
Data update process is not allowed to repeatedly execute data update.
design:
1, front-end design
(1) Click the button, ajax post request to start an asynchronous thread to update the data, and calls the results of the interface;
(2) Results of the interface, the query execution result every 2 seconds, until the end of execution.
Binding bootstrap mode frame design Page:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
< The INPUT of the type = "the Button" value = "update users concerned about the state of" the above mentioned id = "updateSubscribe" /> <!-- 模态框(Modal) --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4><span class="label bg-danger">更新微信用户关注状态</span></h4> </div> <div class="modal-body"> <section class="panel text-center"> <a class="btn btn-circle btn-facebook btn-large"><i class="icon-facebook"></i></a> <div class="h4"> Are checking micro-channel users concerned about the public status ... No. Wait! Close does not affect the business. </ Div > < div class = "Line ml mr" > </ div > < h4 class = "text-info" > < strong the above mentioned id = "msg" > Refreshing ... </ strong > </ H4 > < Small > * Represents results of blue </ Small > </ sectionTop > </ div > < div class = "Modal-footer" > < class="btn btn-default" data-dismiss="modal">关闭</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal --> </div>
JS achieve the following:
$("#updateSubscribe").click(function(){ $('#myModal').modal('show'); $.ajax({ type: "POST", cache: false , url: "/updateSubscribe", dataType: 'json', success: function (data) { if (data.errcode!='0') { $("#msg").html(data['errmsg']); } updateResult(); } }); }); var updateResult = function(){ $.ajax({ type: "POST", cache: false , url: "/updateSubscribeResult", dataType: 'json', success: function (data) { if(data.success){ $("#msg").html(data.message); }else{ setTimeout(function () { updateResult(); }, 2000); } } }); }
2, back-end design
Use springboot build a framework
(1)Controller
We need to determine whether there is a thread that there is not allowed to update data; it does not exist create a new thread to update the data to ensure that only one thread is currently processing data update.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Controller public class UpdateSubscribeController { @Autowired private UpdateSubscribeService updateSubscribeService; @PostMapping(value = "/updateSubscribe") @ResponseBody public ResultBean get(){ ResultBean resultBean = new ResultBean(); Thread thread = getThreadByName("UpdateSubscribe"); if(null == thread){ UpdateSubscribeThread updateSubscribeThread = new UpdateSubscribeThread(updateSubscribeService); updateSubscribeThread.setName("UpdateSubscribe"); updateSubscribeThread.start(); }else { resultBean.setError(ErrorCode.SYSTEM_ERROR); resultBean.setErrmsg ( "the last update is not over yet, do not repeat the update." ); } return resultBean; } @PostMapping(value = "/updateSubscribeResult") @ResponseBody public JsonResult updateSubscribeResult(){ JsonResult result = new JsonResult(); result.setSuccess(false); Thread thread = getThreadByName("UpdateSubscribe"); if(null == thread){ // 更新完成 result.setSuccess(true); try { result.setMessage(UpdateSubscribeResultSingleton.getInstance().getErrorMsg()); }catch (Exception e){ e.printStackTrace (); } } return Result; // not yet finished } /** * Get the name of a thread by thread object * @param threadName * @return */ public static Thread getThreadByName(String threadName) { for (Thread t : Thread.getAllStackTraces().keySet()) { if (t.getName().equals(threadName)) { return t; } } return null; } }
(2) thread class UpdateSubscribeThread
public class UpdateSubscribeThread extends Thread{ private UpdateSubscribeService updateSubscribeService; public UpdateSubscribeThread(UpdateSubscribeService updateSubscribeService) { this.updateSubscribeService = updateSubscribeService; } @Override public void run(){ updateSubscribeService.checkSubscribe(); } }
(3) business to achieve class UpdateSubscribeService
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Service public class UpdateSubscribeService { private static final Logger log = LoggerFactory.getLogger(UpdateSubscribeService.class); @Autowired private WxMpService wxMpService; @Autowired private UserDao userDao; @Autowired private WxUserDao wxUserDao; @Autowired private EntityManagerFactory emf; public void checkSubscribe(){ log.info ( "Start :: UpdateSubscribeService ==> checkSubscribe Method: perform asynchronous tasks} {" , Thread.currentThread () getName ().); UpdateSubscribeResultSingleton resultSingleton = UpdateSubscribeResultSingleton.getInstance(); resultSingleton.setSuccess(null); try { // Thread.currentThread().sleep(7000); wxUserDao.deleteAll(); WxMpUserList wxMpUserList = wxMpService.userList(null); Criteria<User> userCriteria = new Criteria<>() ; userCriteria.add(Restrictions.eq("subscribe" ,true)) ; Long userCount = userDao.count(userCriteria); if(wxMpUserList.getTotal() > userCount ){ int check = 0; while(null != wxMpUserList){ check += wxMpUserList.getCount(); wxMpUserList = getNextWxMpUserList(wxMpUserList, check); } EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Query query = em.createNativeQuery("UPDATE user SET subscribe=1 WHERE weixin IN(SELECT id FROM wx_user)"); int num = query.executeUpdate(); log.info ( "{} Update user status is concerned" , NUM); query = em.createNativeQuery("UPDATE user SET subscribe=0 WHERE weixin not IN(SELECT id FROM wx_user)"); int result2 = query.executeUpdate(); log.info ( "{} Update user is not concerned about the state" , result2); em.getTransaction().commit(); query = em.createNativeQuery("SELECT wu.* FROM wx_user wu left join user u ON wu.id=u.weixin WHERE u.weixin IS NULL",WxUser.class); List<WxUser> list = query.getResultList(); Date nowTime = new Date(); for(WxUser wxUser : list){ String openId = wxUser.getId(); WxMpUser wxMpUser = wxMpService.userInfo(openId,"zh_CN"); log.info ( "Follow user manually added {} :: -> {}" , OpenID, wxMpUser.getNickname ()); User user = new User(); user.setWeixin(openId); user.setName(wxMpUser.getNickname()); user.setUnionId(wxMpUser.getUnionId()); user.setUrl(wxMpUser.getHeadImgUrl()); user.setCreateAt(nowTime); user.setLastLogin(nowTime); user.setSubscribe(true); userDao.saveAndFlush(user); } em.close(); } log.info ( "End :: UpdateSubscribeService ==> Method, checkSubscribe: asynchronous task execution" ); resultSingleton.setSuccess(true); resultSingleton.setErrorMsg ( "Update successful" ); resultSingleton.setLastUpdateTime(new Date()); } catch (Exception e) { log.info ( "UpdateSubscribeService ==> checkSubscribe Method: perform asynchronous task failed because the {} ::" , e.toString ()); e.printStackTrace (); resultSingleton.setSuccess(false); resultSingleton.setErrorMsg ( "update failed because ::" + e.toString ()); resultSingleton.setLastUpdateTime(new Date()); } } private WxMpUserList getNextWxMpUserList(WxMpUserList wxMpUserList , int check) throws WxErrorException { List<String> openIdList = wxMpUserList.getOpenIds(); List<WxUser> wxUserList = new ArrayList<>(); for(String openId : openIdList){ WxUser wxUser = new WxUser(); wxUser.setId(openId); wxUserList.add(wxUser); } wxUserDao.save(wxUserList); if(check == wxMpUserList.getTotal()){ return null; } return wxMpService.userList(null); } }
(4) Design singleton thread execution results stored
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class UpdateSubscribeResultSingleton { private static class UpdateSubscribeResultHandler{ private static UpdateSubscribeResultSingleton intstance = new UpdateSubscribeResultSingleton(); } private UpdateSubscribeResultSingleton(){ } public static UpdateSubscribeResultSingleton getInstance(){ return UpdateSubscribeResultHandler.intstance; } private Boolean isSuccess; private String errorMsg ; private Date lastUpdateTime; public Boolean getSuccess() { return isSuccess; } public void setSuccess(Boolean success) { isSuccess = success; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } public Date getLastUpdateTime() { return lastUpdateTime; } public void setLastUpdateTime(Date lastUpdateTime) { this.lastUpdateTime = lastUpdateTime; } }