项目作到一半技术经理辞职了,留个烂摊子。web基本已作完,安卓的app要新写,项目开发完作个总结,这东西已是很久前作的了。html
登陆接口很快就写好了,登陆成功后用户信息是缓存再session当中的java
/** * 用户登陆 * * @param user * @return */ @RequestMapping(value = "doLogin") @ResponseBody public Map doLogin(User user, HttpServletRequest request) { Map result = Maps.newHashMap(); try { LoginResult flag = FrontUserUtils.doLogin(user, request); if (flag == LoginResult.登陆成功) { Map<String, Object> map = new HashMap<>(); String[] propertys = new String[]{"name", "photo", "singleId"}; for (String property : propertys) { map.put(property, Reflections.invokeGetter(FrontUserUtils.getUserBySession(), property)); } result.put("flag", 1); result.put("user", map); return result; } else if (flag == LoginResult.用户被锁定) { result.put("flag", 0); result.put("msg", "用户被锁定,请联系管理员!"); return result; } else if (flag == LoginResult.登陆失败) { result.put("flag", 0); result.put("msg", "帐号或密码错误!"); return result; } } catch (Exception e) { result.put("flag", 0); result.put("msg", "操做失败!"); e.printStackTrace(); } return result; }
/
可是登陆成功后,再调用其余须要获取登陆用户信息的时候的时候发如今session中没有,不对啊,明明自已用浏览器测试是OK的啊,我本身补不了解嘛,web
技术经理也跑了,不知道怎么回事啊、咋整,我去问安卓,他也不懂啊,我也走吧。json
而后debug测试吧,用浏览器不这样啊,session是同一个呐。测试一下,在后台打印一下sessionid:浏览器
浏览器访问接口:缓存
模拟安卓访问接口:服务器
每次都生成了新的session,这么搞不行啊,每次请求都生成新session,我怎么缓存你登陆用户的信息啊。cookie
而后就想办法解决啊 ,想来想去想了两个方案网络
方案1:自定义身份识别方式(token),相似本身模拟sessionsession
再用户登陆之后,在系统内生成一个惟一的身份标识,并将此标识返回给客户端。身份标识保存15天,若是用户,在其余终端登陆,或者15天超时在服务器没有业务,将通知终端会话超时,从新登陆。
后台代码就不贴了,使用的uuid生成的一个字符串,做为用户的登陆标识,将用户信息写入缓存,相似key :user这种方式存储。
用户请求其余接口的时候,会被个人一个拦截器拦截,若是发现根据字符串查询用户查询不到,就会将用户剔除系统。
拦截器:
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { User user = FrontUserUtils.getUser(); if (user == null || user.getId() == null || user.getId().equals("")) { returnJson(httpServletResponse); return false; } else { return true; } } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { e.notifyAll(); } private void returnJson(HttpServletResponse response) throws Exception { PrintWriter writer = null; response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=utf-8"); try { Map map = new HashMap(); map.put("flag", 0); map.put("msg", "登录会话已通过期,请从新登录!"); JSONObject jsonObject = JSONObject.fromObject(map); writer = response.getWriter(); writer.print(jsonObject); } catch (IOException e) { } finally { if (writer != null) writer.close(); } } }
这样写,牺牲掉了一部分系统性能,来实现安卓与服务器之间的长链接,由于基本拦截了全部的接口,每次都判断是否登陆,或者登陆超时。
方案2:仍是使用sessionId,其实两种方式都差很少,不过我仍是推荐这种,第一种的花同一时间用户太多,session过多,可能致使其余的问题。
web浏览器保持会话,是由于有session的存在,不一样的服务器在浏览器请求的时候会判断是否为第一次请求,若是是第一次就回返回一个参数Set-Cookie,通常浏览器支持本身保存这个数据,这个数据也是浏览器与服务器保持会话的标识;
好比以百度为例:
再次请求相同的服务器,浏览器会从cookie中取出这些这值,加载到浏览器的请求中去
浏览器若是不由用cookie的话,浏览器就会将服务器返回的数据保存到cookie当中去,session与cookie不清楚的,去查资料吧。
安卓的访问方式
尽管安卓可使用许多网络框架来进行访问,可是我不是很了解呐,加上公司的安卓开发也不甚了解,
我以为他是使用httpclient相似的方式来进行访问的,我就谢了一个代码模拟了下安卓的请求,来获取下服务器返回的数据,看能不能获取到 Set-Cookie;
public class MainActivity { public static final String login_url="http://192.168.0.112:8080/login/doLogin?loginName=18866601116&password=123456zxc"; /** * 安卓登陆测试 * @param args * @throws Exception */ public static void main(String[] args) throws Exception { URL url=new URL(login_url); HttpURLConnection con=(HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); String cookieString=con.getHeaderField("Set-Cookie"); System.out.print(cookieString); } }
//控制台输出
哎能够的。就让安卓再第一次请求服务器的时候将这个sessionid保存下来吧,缓存到手机,
而后请求后台的时候,将保存的cookie放在httpPost的请求当中,这样访问服务器时,服务器就会认为是同一个用户了。也就是说保持了这个会话。
其实两种方式的原理都差很少,若是有更好的方案,也能够跟我说,学习嘛。