上篇文章介绍简单启动Jetty+Jersey服务,并可以通过Jmeter进行简单测试。本章再深入搭建一个Service+Action的框架,还会引入JSON解析工具。
请求的执行流程:
web前端 -> Service接口(通过@Path(xxx)访问) -> AbstractAction -> json解析成请求体req -> Action中的校验validate -> Action中的doAction -> 将返回体转换成json字符串 -> 转换成Response -> 返回给Web前端
包以及类分布:
各个类源码:
FrameworkErrorCode:
/**
* 2017年4月29日 黑苹果
*/
package com.black.apple.framework.exception;
/**
* @author 黑苹果 2017年4月29日
*/
public enum FrameworkErrorCode
{
/**
* 成功
*/
OK(0),
/**
* Jersey服务启动失败
*/
JERSEY_SERVICE_START_FAILED(1),
/**
* JSON解析异常
*/
JSON_DECODE_EXCEPTION(2),
/**
* 参数非法
*/
PARAM_INVALID(3),
/**
* 未知异常
*/
UNKNOW_EXCEPTION(9999);
private int errorCode;
/**
* 错误码范围为:10000000~10009999
*/
private static final int ERROR_CODE_PREFIX = 1000_0000;
private FrameworkErrorCode(int errorCode)
{
this.errorCode = ERROR_CODE_PREFIX + errorCode;
}
public String toString()
{
return String.valueOf(errorCode);
}
}
AbstractAction:
/**
* 2017年4月29日 黑苹果
*/
package com.black.apple.framework.jersey.rest.action.abs;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.black.apple.framework.exception.FrameworkErrorCode;
import com.black.apple.framework.exception.FrameworkException;
import com.black.apple.framework.jersey.utils.JsonDecodeUtil;
/**
* @author 黑苹果 2017年4月29日
*/
public abstract class AbstractAction<S, T>
{
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAction.class);
/**
* Action主方法
*
* @param content
* json串
* @return Response
*/
public Response execute(String content)
{
Response response;
try
{
S s = decodeJson(content);
validateParam(s);
T t = doAction(s);
String responseJson = encodeJson(t);
response = buildSuccessResponse(responseJson);
}
catch (FrameworkException e)
{
LOGGER.error("FrameworkException.", e);
response = buildErrorResponse(e);
}
catch (Exception e)
{
LOGGER.error("Exception.", e);
response = buildErrorResponse(e);
}
return response;
}
private Response buildErrorResponse(Exception e)
{
return Response
.status(Status.SERVICE_UNAVAILABLE)
.type(MediaType.APPLICATION_JSON)
.entity(encodeJson(new ErrorResp(FrameworkErrorCode.UNKNOW_EXCEPTION.toString(),
FrameworkErrorCode.UNKNOW_EXCEPTION.toString()))).build();
}
private Response buildErrorResponse(FrameworkException e)
{
return Response.status(Status.SERVICE_UNAVAILABLE).type(MediaType.APPLICATION_JSON)
.entity(encodeJson(new ErrorResp(e.getErrorCode(), e.getErrorCode()))).build();
}
private Response buildSuccessResponse(String responseJson)
{
return Response.ok(responseJson, MediaType.APPLICATION_JSON).build();
}
private S decodeJson(String json) throws FrameworkException
{
return JsonDecodeUtil.decode(json, getRequestClassType());
}
@SuppressWarnings("unchecked")
private Class<S> getRequestClassType()
{
Type genType = getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
Class<S> sClass = (Class<S>) params[0];
return sClass;
}
private <O> String encodeJson(O obj)
{
try
{
String json = JsonDecodeUtil.encode(obj);
return json;
}
catch (FrameworkException e)
{
LOGGER.error("json decode failed.obj={}", obj, e);
}
return StringUtils.EMPTY;
}
protected abstract T doAction(S request) throws FrameworkException;
protected abstract void validateParam(S request) throws FrameworkException;
}
ErrorResp:
/**
* 2017年4月29日 黑苹果
*/
package com.black.apple.framework.jersey.rest.action.abs;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* @author 黑苹果 2017年4月29日
*/
public class ErrorResp
{
private String errorCode;
private String errorMsg;
/**
* @param errorCode
* @param errorM
*/
public ErrorResp(String errorCode, String errorMsg)
{
super();
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
/**
* @return the errorCode
*/
public String getErrorCode()
{
return errorCode;
}
/**
* @return the errorMsg
*/
public String getErrorMsg()
{
return errorMsg;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("errorCode", errorCode)
.append("errorMsg", errorMsg).build();
}
}
TestAction:
/**
* 2017年4月29日 黑苹果
*/
package com.black.apple.framework.jersey.rest.action;
import java.util.HashMap;
import java.util.Map;
import com.black.apple.framework.exception.FrameworkErrorCode;
import com.black.apple.framework.exception.FrameworkException;
import com.black.apple.framework.jersey.rest.action.abs.AbstractAction;
import com.black.apple.framework.jersey.rest.req.TestReq;
import com.black.apple.framework.jersey.rest.resp.TestResp;
/**
* @author 黑苹果 2017年4月29日
*/
public class TestAction extends AbstractAction<TestReq, TestResp>
{
private Map<String, String> valueMap = new HashMap<String, String>();
public TestAction()
{
valueMap.put("key1", "value1");
valueMap.put("key2", "value2");
valueMap.put("key3", "value3");
}
/*
* (non-Javadoc)
*
* @see
* com.black.apple.framework.jersey.rest.action.abs.AbstractAction#doAction
* (java.lang.Object)
*/
@Override
protected TestResp doAction(TestReq request) throws FrameworkException
{
String key = request.getKey();
String value = valueMap.get(key);
TestResp resp = new TestResp();
resp.setValue(value);
return resp;
}
/*
* (non-Javadoc)
*
* @see
* com.black.apple.framework.jersey.rest.action.abs.AbstractAction#validateParam
* (java.lang.Object)
*/
@Override
protected void validateParam(TestReq request) throws FrameworkException
{
String key = request.getKey();
if (valueMap.containsKey(key))
{
return;
}
throw new FrameworkException(FrameworkErrorCode.PARAM_INVALID);
}
}
TestReq:
/**
* 2017年4月29日 黑苹果
*/
package com.black.apple.framework.jersey.rest.req;
/**
* @author 黑苹果 2017年4月29日
*/
public class TestReq
{
private String key;
/**
* @return the key
*/
public String getKey()
{
return key;
}
/**
* @param key
* the key to set
*/
public void setKey(String key)
{
this.key = key;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "TestReq [key=" + key + "]";
}
}
TestResp:
/**
* 2017年4月29日
* 黑苹果
*/
package com.black.apple.framework.jersey.rest.resp;
/**
* @author 黑苹果
* 2017年4月29日
*/
public class TestResp
{
private String value;
/**
* @return the value
*/
public String getValue()
{
return value;
}
/**
* @param value the value to set
*/
public void setValue(String value)
{
this.value = value;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "TestResp [value=" + value + "]";
}
}
TestService:
/**
* 2017年4月29日 黑苹果
*/
package com.black.apple.framework.jersey.rest.service;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.black.apple.framework.jersey.rest.action.TestAction;
/**
* @author 黑苹果 2017年4月29日
*/
@Path("framework")
public class TestService
{
@POST
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public Response test(String content)
{
return new TestAction().execute(content);
}
}
/**
*
*/
package com.black.apple.framework.jersey.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.black.apple.framework.exception.FrameworkErrorCode;
import com.black.apple.framework.exception.FrameworkException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author 黑苹果
*
*/
public final class JsonDecodeUtil
{
private static final Logger LOGGER = LoggerFactory.getLogger(JsonDecodeUtil.class);
private static ObjectMapper mapper = null;
static
{
mapper = new ObjectMapper();
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
}
/**
* Json转换
*
* @param object
* 待转JSON的对象
* @return json串
* @throws TosException
*/
public static <T> String encode(T object) throws FrameworkException
{
try
{
String json = mapper.writeValueAsString(object);
return json;
}
catch (JsonProcessingException e)
{
LOGGER.error("json encode failed.object={}", object, e);
throw new FrameworkException(FrameworkErrorCode.JSON_DECODE_EXCEPTION, e);
}
}
/**
* Json解析
*
* @param json
* json串
* @param clazz
* 目标类
* @return 目标实例
*/
public static <T> T decode(String json, Class<T> clazz) throws FrameworkException
{
try
{
T result = mapper.readValue(json, clazz);
return result;
}
catch (Exception e)
{
LOGGER.error("json decode failed. json={}, clazz={}", json, clazz, e);
throw new FrameworkException(FrameworkErrorCode.JSON_DECODE_EXCEPTION, e);
}
}
}
log4j.properties:
log4j.rootCategory=INFO, stdout ,R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=logs/run.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
Jmeter测试: