上一篇博客中已经简单的整理了移动端调用PC端接口的实现流程,这其中涉及到springMVC拦截器的使用。下面通代码对应上篇博客中的流程简介看一下具体是如何实现的。首先定义一个拦截器,需要实现HandlerInterceptor接口,这个接口有三个方法,在这里的作用是验证用户是否登录,所用只用preHandle这个方法就可以完成。首先需要建立两个类,InDto和OutDto分别是信息接收实体和信息反馈实体。
InDto:主要是用来接收移动端URL请求的参数包括请求的controller、方法、参数。
<span style="font-size:18px;">/**
* <p>Title:InDto</p>
* Description:参数接收实体类
*/
public class InDto {
/**
* 版本号
*一般为固定的,主要是为了和Action进行凭借识别对应的controller
*/
private String version;
/**
* 方法包名
*/
private String action;
/**
* 方法名
*/
private String method;
/**
* 时间戳
*/
private String timeStamp;
/**
* 请求参数
*/
private String req;
/**
* 接口请求request
*/
private HttpServletRequest request;
/**
* 接口请求response
*/
private HttpServletResponse response;
/**
* 注入
*/
private Object dao;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getReq() {
return req;
}
public void setReq(String req) {
this.req = req;
}
public Object getDao() {
return dao;
}
public void setDao(Object dao) {
this.dao = dao;
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletResponse getResponse() {
return response;
}
public void setResponse(HttpServletResponse response) {
this.response = response;
}
//构造函数
public InDto(Map<String,String[]> map) throws IOException{
this.version=map.get("Version")!=null?map.get("Version")[0]:"";
this.action=map.get("Action")!=null?map.get("Action")[0]:"";
this.method=map.get("Method")!=null?map.get("Method")[0]:"";
this.timeStamp=map.get("TimeStamp")!=null?map.get("TimeStamp")[0]:"";
this.req=map.get("Req")!=null?map.get("Req")[0]:"";
}
}
</span>
OutDto:主要用来返回约定的编码,方便移动端确定请求成功、失败、或者服务器请求失败。
<span style="font-size:18px;">/**
* <p>Title:OutDto</p>
* Description: 信息反馈实体类
*/
public class OutDto {
/**
* 成功
*/
public static final String STATUS_SUCCESS="100";
/**
* 失败
*/
public static final String STATUS_FAIL="200";
/**
* 服务端异常
*/
public static final String STATUS_EXCEPTION="300";
/**
* 代码标识
*/
private String status;
/**
* 信息
*/
private String msg;
/**
* 返回数据
*/
private Object data;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/**
* @描述 设置失败状态
*/
public void setStatusFail() {
this.status = STATUS_FAIL;
}
/**
* @描述 设置失败状态和消息
*/
public void setStatusFail(String msg) {
this.status = STATUS_FAIL;
this.msg=msg;
}
/**
* @描述 设置成功状态
*/
public void setStatusSuccess() {
this.status = STATUS_SUCCESS;
}
/**
* @描述 设置成功状态并插入data数据
* @author quzf
*/
public void setStatusSuccess(Object data,String msg) {
this.status = STATUS_SUCCESS;
this.data=data;
this.msg=msg;
}
/**
* @描述 设置成功状态并插入data数据
*/
public void setStatusSuccess(String msg) {
this.status = STATUS_SUCCESS;
this.msg=msg;
this.data="";
}
}
</span>
移动端约定的请求接口的URL:
http://localhost:8080/test/Service/dataSync.do?&Version=1.0&Action=login&Method=Login &TimeStamp=10000&Req={"params":{
"userName": "admin",
"userPwd ": "123456"
}
}
编写一个拦截器实现接口HandlerInterceptor
<span style="font-size:18px;">/**
*
*拦截器
*/
public class DataSyncInterceptor implements HandlerInterceptor {
@Autowired
private OrganService organService;
/**
* @描述 验证用户名密码是否正确
*/
public OutDto testLegal(HttpServletRequest request) throws Exception {
//实例化一个InDto,同时获得了客户端传来的信息
InDto inDto=new InDto(request.getParameterMap());
JSONObject reqJSON = JSON.parseObject(inDto.getReq());
String action = inDto.getAction();//获取到请求的Action
OutDto outDto=new OutDto();
if(action.equals("login")){//如果是登录进行验证
String userName = reqJSON.getString("userName");
String userPwd = reqJSON.getString("userPwd");
User user = organService.login(userName, userPwd);
if(user==null){
outDto.setStatusFail();
outDto.setMsg("用户名或密码不正确!");
}else{
outDto.setStatusSuccess();
}
return outDto;
}
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object o) throws Exception {
//请求参数注入InDto
OutDto outDto=new OutDto();
try {
InDto inDto=new InDto(request.getParameterMap());
//设置验证结果,先不走验证非法,直接返回成功
outDto = testLegal(request);
//参数验证结果成功后,执行下面的拦截器
if(OutDto.STATUS_SUCCESS.equals(outDto.getStatus())){
return true;
}else{
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print(JsonUtil.object2json(outDto));
out.close();
return false;
}
} catch (Exception e) {
response.setCharacterEncoding("UTF-8");
outDto.setStatus(OutDto.STATUS_EXCEPTION);//异常时
PrintWriter out = response.getWriter();
out.print(JsonUtil.object2json(outDto));
e.printStackTrace();
out.close();
return false;
}
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
}
}
</span>
拦截器配置到mvc的配置文件中:
<mvc:interceptors> <mvc:interceptor> <!-- //映射路径后缀名 --> <mvc:mapping path="/Service/*"/> <!--//自定义拦截器 --> <bean class="interceptor.DataSyncInterceptor"/> </mvc:interceptor> </mvc:interceptors>
拦截器走完如果用户验证通过后preHandle方法返回true,由于没有配置其他的拦截器就会根据请求的URL开始调用对应的controller。请求的URL中有“http://localhost:1080/test/Service/dataSync.do” 所以会根据URL找到Service这个controller中的dataSync方法。
<span style="font-size:18px;">/**
* <p>Title:ServiceController</p>
* Description: 移动端接口入口
*/
@Controller
@RequestMapping("Service")
public class ServiceController{
@RequestMapping({"/dataSync"})
@ResponseBody
public void dataSync(HttpServletRequest request, HttpServletResponse response) {
OutDto outDto = new OutDto();
try {
InDto inDto=new InDto(request.getParameterMap());
inDto.setRequest(request);
inDto.setResponse(response);
String method = inDto.getMethod();
if(StringUtils.isBlank(method)){
method=AtcConstant.getAtcClassMethod();
}
//依据action和method,然后读取配置中的类反射执行该class
Object bean = SpringHelper.getBean(inDto.getAction()+inDto.getVersion());
outDto=(OutDto) ReflectUtil.invoke(bean,method, inDto,outDto);
} catch (Exception e) {
outDto.setStatus(OutDto.STATUS_EXCEPTION);
e.printStackTrace();
}
try {
//返回的结构为字节流是调用,为移动端做附件下载时使用
if ("返回流".equals(outDto.getMsg())) {
OutputStream outputStream=response.getOutputStream();
InputStream is=new FileInputStream(outDto.getData().toString());
byte b[] = new byte[1024];
int len = -1;
while ((len = is.read(b)) != -1)
outputStream.write(b, 0, len);
is.close();
outputStream.close();
}else { //非字节流结果返回时调用
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print(JsonUtil.object2json(outDto));
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
</span>
这个方法中的核心代码是:
String method = inDto.getMethod();
Object bean =SpringHelper.getBean(inDto.getAction()+inDto.getVersion());
outDto=(OutDto)ReflectUtil.invoke(bean,method, inDto,outDto);
根据请求的Action+Version 可以确定要调用的Controller,用ReflectUtil中的invoke方法,将得到的实体bean和要调用的方法名称作为参数传递就可以调用相应controller中的方法。以这次的登录为例Action=login;Version =1.0就会请求名为login1.0的Controller中的Login方法。在这个controller的方法中就可以写系统的业务逻辑代码。
小结:
移动端调用接口的代码实现就是这样的,通过拦截器进行登录验证,使用invoke调用请求的controller中的方法。