Restful后台系统搭建(四)

上篇文章介绍简单启动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);
    }
}


JsonDecodeUtil:

/**
 * 
 */
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测试:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值