手机 API 接口调用、前后分离 ## <http://jeesite.com/?t=270527> 有不少朋友咨询我,想用JeeSite做前后分开的应用,或者手机端API怎么调用?又或者只想用JeeSite作为服务端API,仅提供服务接口怎么做?那这篇文章一定适合你,下面我来介绍下一些JeeSite已内置的接口及如果自己来开发API接口提供服务。 # 内置接口 ## 系统登录 JeeSite的系统默认登录,设置了DES加密,如果不想加密,可将secretKey设置为空即可,或更改密钥,配置如下`application.yml`(v4.0.x:`jeesite.yml`): ``` shiro: loginSubmit: # 登录提交信息安全Key,加密用户名、密码、验证码,后再提交(key设置为3个,用逗号分隔) secretKey: thinkgem,jeesite,com # 设置为空,关闭登录DES加密。 # secretKey: ~ # 如果是JS请求可能会有跨域访问问题,可将如下参数设置为,允许的域名,全部域名设置*号,否则设置为空 accessControlAllowOrigin: '*' ``` 如果开启了加密,你就需要先将DES加密工具引入: JS:`<script src="${ctxStatic}/common/des.js?${_version}"></script>` Java: `com.jeesite.common.codec.DesUtils` 引入完成之后就可以通过如下方法进行调用加密了: JS: ``` <script> var secretKey = '${@Global.getConfig("shiro.loginSubmit.secretKey")}'; var username = DesUtils.encode('system', secretKey); var password = DesUtils.encode('admin', secretKey); console.log('&username=' + username + '&password=' + password); </script> ``` Java: ``` String secretKey = Global.getConfig("shiro.loginSubmit.secretKey"); String username = DesUtils.encode("system", secretKey); String password = DesUtils.encode("admin", secretKey); System.out.println("&username=" + username + "&password=" + password); ``` 以上两种语言,输出结果相同如下: ``` &username=F3EDC7D2C193E0B8DCF554C726719ED2&password=235880C505ACCDA5C581A4F4CDB81DA0 ``` 下面我们就可以拿着这个用户名密码进行测试登录了。 通过JS的Ajax或者通过Java的HttpClient进行POST或GET请求如下地址,即可进行登录验证: ``` http://127.0.0.1:8980/js/a/login?__login=true&__ajax=json&username=F3EDC7D2C193E0B8DCF554C726719ED2&password=235880C505ACCDA5C581A4F4CDB81DA0 ``` 你也可以添加登录附加参数如下: ``` 1、可以指定登录设备类型(在线用户列表区分、登录验证码按设备区分,可根据设备指定session超时时间,默认PC): ¶m_deviceType=mobileApp 2、可以指定登录的系统(区分不同的菜单,默认default) ¶m_sysCode=mobileApp 3、可以指定登录页面和主框架页的视图(默认:employee) ¶m_userType=member ``` 若登录信息不正确,则返回如下失败JSON数据: ``` { "username": "F3EDC7D2C193E110B8DCF554C726719ED2", "rememberMe": false, "rememberUserCode": false, "params": "", "shiroLoginFailure": "org.apache.shiro.authc.UnknownAccountException", "message": "账号或密码错误, 请重试.", "isValidCodeLogin": false, "result": "false", "sessionid":"2a6669501bf24afebcf4ff63eb048a56" } ``` 如果失败,第二次登录,建议附加一个__sid参数,用来指明是同一个会话,如: ``` http://127.0.0.1:8980/js/a/login?__login=true&__ajax=json&username=F3EDC7D2C193E0B8DCF554C726719ED2&password=235880C505ACCDA5C581A4F4CDB81DA0&__sid=2a6669501bf24afebcf4ff63eb048a56 ``` 注意:若参数配置的密码失败次数超过了预警值,则返回的结果信息中的`isValidCodeLogin`会变为`true`,这时你需要调用`http://127.0.0.1:8980/js/validCode?__sid=2a6669501bf24afebcf4ff63eb048a56`地址来获取验证码图片,另外请注意,移动端一般调用是无cookie的,建议加请求参数中要包含__sid参数,否则获取到的验证码值将无法与你登录请求会话匹配。 若登录信息正确,则返回如下登录成功JSON数据: ``` { "user": { "id": "system", "status": "0", "remarks": "", "userCode": "system", "loginCode": "system", "userName": "超级管理员", "userType": "none", "mgrType": "0", "lastLoginIp": "127.0.0.1", "lastLoginDate": "2018-03-14 22:34:44", "userWeight": 0, "oldLastLoginIp": "127.0.0.1", "corpName_": "JeeSite", "corpCode_": "0", "oldLoginDate": "2018-03-14 22:34:44", "avatarUrl": "/ctxPath/static/images/user1.jpg" }, "result": "true", "message": "登录成功!", "sessionid": "5fe9c7c45ded4425b03eff8f78179637" } ``` 若返回 `"result":"login"` 则代表,`__sid` 已失效,需要重新登录。 在登录成功的信息里,也有个 sessionid 属性,该属性值将作为你以后访问系统的凭证,相当于token令牌,举例如下: ``` 1、获取用户权限信息: http://127.0.0.1:8980/js/a/authInfo?__sid=5fe9c7c45ded4425b03eff8f78179637 2、获取用户菜单信息: http://127.0.0.1:8980/js/a/menuTree?__sid=5fe9c7c45ded4425b03eff8f78179637 3、重新获取登录信息: http://127.0.0.1:8980/js/a/index.json?__sid=5fe9c7c45ded4425b03eff8f78179637 4、获取当前用户信息: http://127.0.0.1:8980/js/a/sys/user/info.json?__sid=5fe9c7c45ded4425b03eff8f78179637 ``` ### 快速登录接口: 设置 jeesite.yml 的 shiro.sso.secretKey 快速登录安全Key,登录接口如下: ``` /** * 单点登录(如已经登录,则直接跳转) * @param username 登录用户名(loginCode) * @param token 登录令牌,令牌组成:sso密钥+用户名+日期,进行md5加密,举例: * String secretKey = Global.getConfig("shiro.sso.secretKey"); * String token = Md5Utils.md5(secretKey + username + DateUtils.getDate("yyyyMMdd")); * @param params 登录附加参数(JSON格式),或 param_ 前缀的请求参数。 * @param url 登录成功后跳转的url地址。 * @param relogin 是否重新登录,需要重新登录传递true */ @RequestMapping(value = "sso/{username}/{token}") public String sso(@PathVariable String username, @PathVariable String token, HttpServletRequest request, @RequestParam(defaultValue="${adminPath}") String url, String relogin, Model model) ``` 调用地址例如: ``` http://localhost/project/sso/{username}/{token}?url=/sys/user/list?p1=v1%26p2=v2&relogin=true ``` 如果url中带参数,请使用转义字符,如“&”号,使用“%26”转义。 ## 系统退出 ``` http://127.0.0.1:8980/js/a/logout?__ajax=json&__sid=5fe9c7c45ded4425b03eff8f78179637 ``` 注意:无cookie环境下,必须要指定要退出的sessionid 返回JSON数据: ``` {"result":"true","message":"退出成功!"} ``` # 接口发现 剩下的接口就不一一说明了,交给大家一个接口发现的方法。 所有连接加 .json 或 .xml 或增加 `__ajax=json` 参数,或增加 `__ajax=xml` 参数,则自动返回 json 或 xml 数据,而不返回视图,举例: 用户列表的访问地址是 /a/sys/empUser/list,如果直接访问,则返回页面的视图界面,如果加后缀 .json,则返回视图所需要的json数据,如:/a/sys/empUser/list.json,这样返回的数据,就可以在你的前端分离应用中使用了。 所有列表加载的数据均使用 listData 为后缀获取数据,如用户列表的数据地址为 /a/sys/empUser/listData,则直接返回JSON数据。 listData只是一个命名规则,如果你发现了不遵循规范的地址,怎么办?你可以通过Chrome浏览器的开发者界面(F12),打开Network,Filter中选择XHR,好了,准备就绪,这是你点击列表里的查询按钮,即可监控到访问的数据的地址是什么 # 开发一个API接口 在你的Controller映射方法上增加@ResponseBody即可返回JSON数据,而不返回视图 或者替换@Controller为@RestController,则应用所有映射方法均返回JSON数据。 如果你想两用,就如 接口发现 章节所述,增加 .json 后缀即可。 另外,对于移动端或高并发的应用对于流量是非常珍贵的,通过通用方法可能会返回一些很多无用的数据,这时,你最好单独覆写Rest清理无用的数据为null,则不会返回到前台。