diff --git a/pig-admin-service/src/main/java/com/github/pig/admin/common/listener/LogReceiveListener.java b/pig-admin-service/src/main/java/com/github/pig/admin/common/listener/LogReceiveListener.java index 6f05df90..fbb72bf1 100644 --- a/pig-admin-service/src/main/java/com/github/pig/admin/common/listener/LogReceiveListener.java +++ b/pig-admin-service/src/main/java/com/github/pig/admin/common/listener/LogReceiveListener.java @@ -26,13 +26,12 @@ public class LogReceiveListener { @RabbitHandler public void receive(LogVo logVo) { + System.out.println(logVo.getSysLog()); SysLog sysLog = logVo.getSysLog(); - if (StringUtils.isNotEmpty(logVo.getToken())) { - String username = UserUtils.getUserName(logVo.getToken()); - MDC.put(KEY_USER, username); - sysLog.setCreateBy(username); - sysLogService.insert(sysLog); - MDC.remove(KEY_USER); - } + String username = UserUtils.getUserName(logVo.getToken()); + MDC.put(KEY_USER, username); + sysLog.setCreateBy(username); + sysLogService.insert(sysLog); + MDC.remove(KEY_USER); } } diff --git a/pig-admin-service/src/main/java/com/github/pig/admin/controller/LogController.java b/pig-admin-service/src/main/java/com/github/pig/admin/controller/LogController.java index 2badf745..18bd92e8 100644 --- a/pig-admin-service/src/main/java/com/github/pig/admin/controller/LogController.java +++ b/pig-admin-service/src/main/java/com/github/pig/admin/controller/LogController.java @@ -47,6 +47,7 @@ public class LogController extends BaseController { */ @DeleteMapping("/{id}") public R delete(@PathVariable Integer id) { + int o = 11 / 0; return new R<>(sysLogService.updateByLogId(id)); } } diff --git a/pig-admin-service/src/main/resources/mapper/SysLogMapper.xml b/pig-admin-service/src/main/resources/mapper/SysLogMapper.xml index 5fd5f31b..46d54e4c 100644 --- a/pig-admin-service/src/main/resources/mapper/SysLogMapper.xml +++ b/pig-admin-service/src/main/resources/mapper/SysLogMapper.xml @@ -17,6 +17,7 @@ + diff --git a/pig-admin-service/src/test/java/com/github/pig/admin/controller/UserControllerTest.java b/pig-admin-service/src/test/java/com/github/pig/admin/controller/UserControllerTest.java new file mode 100644 index 00000000..7cdd5de7 --- /dev/null +++ b/pig-admin-service/src/test/java/com/github/pig/admin/controller/UserControllerTest.java @@ -0,0 +1,63 @@ +package com.github.pig.admin.controller; + +import com.github.pig.admin.dto.UserDto; +import com.xiaoleilu.hutool.http.HttpUtil; +import com.xiaoleilu.hutool.json.JSON; +import com.xiaoleilu.hutool.json.JSONUtil; +import org.apache.commons.collections.MapUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + + +/** + * @author lengleng + * @date 2017/12/25 + * UserController单元测试 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class UserControllerTest { + @Autowired + private WebApplicationContext webApplicationContext; + + private MockMvc mockMvc; + + @Before + public void setUp() throws Exception { + mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + } + + @Test + public void testUserGet() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/user/{id}", 1) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.username").value("admin")); + } + + @Test + public void testUserAdd() throws Exception { + UserDto userDto = new UserDto(); + userDto.setRole(1); + userDto.setNewpassword1("@1312312"); + mockMvc.perform(MockMvcRequestBuilders.post("/user") + .contentType(MediaType.APPLICATION_JSON) + .content(JSONUtil.toJsonStr(userDto))) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + public void testPostEdu() throws Exception { + System.out.println(HttpUtil.post("http://eco.ahau.edu.cn/jc/dtrans", MapUtils.EMPTY_MAP)); + } +} \ No newline at end of file diff --git a/pig-common/src/main/java/com/github/pig/common/bean/aop/ControllerAop.java b/pig-common/src/main/java/com/github/pig/common/bean/aop/ControllerAop.java index 6c200b0c..37fdcc84 100644 --- a/pig-common/src/main/java/com/github/pig/common/bean/aop/ControllerAop.java +++ b/pig-common/src/main/java/com/github/pig/common/bean/aop/ControllerAop.java @@ -6,6 +6,7 @@ import com.github.pig.common.util.UserUtils; import com.github.pig.common.util.exception.CheckException; import com.github.pig.common.util.exception.UnloginException; import com.github.pig.common.vo.UserVo; +import com.xiaoleilu.hutool.lang.Console; import org.apache.commons.lang.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -102,7 +103,8 @@ public class ControllerAop { result = pjp.proceed(); logger.info(pjp.getSignature() + "use time:" + (System.currentTimeMillis() - startTime)); } catch (Throwable e) { - result = handlerException(pjp, e); + logger.error("异常信息:", e); + throw new RuntimeException(e); } finally { if (StringUtils.isNotEmpty(username)) { UserUtils.clearAllUserInfo(); @@ -111,23 +113,4 @@ public class ControllerAop { return result; } - - private R handlerException(ProceedingJoinPoint pjp, Throwable e) { - R result = new R(); - - // 已知异常 - if (e instanceof CheckException) { - result.setMsg(e.getLocalizedMessage()); - result.setCode(R.FAIL); - } else if (e instanceof UnloginException) { - result.setMsg("Unlogin"); - result.setCode(R.NO_LOGIN); - } else { - logger.error(pjp.getSignature() + " error ", e); - result.setMsg(e.toString()); - result.setCode(R.FAIL); - } - - return result; - } } diff --git a/pig-common/src/main/java/com/github/pig/common/entity/SysLog.java b/pig-common/src/main/java/com/github/pig/common/entity/SysLog.java index f5bd9b13..cc77c223 100644 --- a/pig-common/src/main/java/com/github/pig/common/entity/SysLog.java +++ b/pig-common/src/main/java/com/github/pig/common/entity/SysLog.java @@ -69,6 +69,11 @@ public class SysLog implements Serializable { */ private String delFlag; + /** + * 异常信息 + */ + private String exception; + public Integer getId() { return id; } @@ -173,20 +178,31 @@ public class SysLog implements Serializable { this.delFlag = delFlag; } + public String getException() { + return exception; + } + + public void setException(String exception) { + this.exception = exception; + } + @Override public String toString() { return "SysLog{" + - ", id=" + id + - ", type=" + type + - ", title=" + title + - ", createBy=" + createBy + - ", createDate=" + createTime + + "id=" + id + + ", type='" + type + '\'' + + ", title='" + title + '\'' + + ", createBy='" + createBy + '\'' + + ", createTime=" + createTime + ", updateTime=" + updateTime + - ", remoteAddr=" + remoteAddr + - ", userAgent=" + userAgent + - ", requestUri=" + requestUri + - ", method=" + method + - ", params=" + params + - "}"; + ", remoteAddr='" + remoteAddr + '\'' + + ", userAgent='" + userAgent + '\'' + + ", requestUri='" + requestUri + '\'' + + ", method='" + method + '\'' + + ", params='" + params + '\'' + + ", time=" + time + + ", delFlag='" + delFlag + '\'' + + ", exception='" + exception + '\'' + + '}'; } } diff --git a/pig-common/src/main/java/com/github/pig/common/vo/ErrorPojo.java b/pig-common/src/main/java/com/github/pig/common/vo/ErrorPojo.java new file mode 100644 index 00000000..3f9d317e --- /dev/null +++ b/pig-common/src/main/java/com/github/pig/common/vo/ErrorPojo.java @@ -0,0 +1,74 @@ +package com.github.pig.common.vo; + +import com.alibaba.fastjson.annotation.JSONField; + +import java.io.Serializable; + +/** + * @author lengleng + * @date 2017/12/25 + * spring boot 的异常对象 + */ +public class ErrorPojo implements Serializable { + + @JSONField(name = "timestamp") + private long timestamp; + @JSONField(name = "status") + private int status; + @JSONField(name = "error") + private String error; + @JSONField(name = "exception") + private String exception; + @JSONField(name = "message") + private String message; + @JSONField(name = "path") + private String path; + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getException() { + return exception; + } + + public void setException(String exception) { + this.exception = exception; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/pig-gateway/src/main/java/com/github/pig/gateway/filter/AccessFilter.java b/pig-gateway/src/main/java/com/github/pig/gateway/filter/AccessFilter.java index 225912f4..915fb404 100644 --- a/pig-gateway/src/main/java/com/github/pig/gateway/filter/AccessFilter.java +++ b/pig-gateway/src/main/java/com/github/pig/gateway/filter/AccessFilter.java @@ -2,23 +2,27 @@ package com.github.pig.gateway.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER; + /** * @author lengleng * @date 2017/11/20 + * 在RateLimitPreFilter 之前执行,不然又空指针问题 */ @Component public class AccessFilter extends ZuulFilter { @Override public String filterType() { - return "pre"; + return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { - return 0; + return FORM_BODY_WRAPPER_FILTER_ORDER - 1; } @Override diff --git a/pig-gateway/src/main/java/com/github/pig/gateway/filter/ErrorHandlerFilter.java b/pig-gateway/src/main/java/com/github/pig/gateway/filter/ErrorHandlerFilter.java new file mode 100644 index 00000000..a22ec3b9 --- /dev/null +++ b/pig-gateway/src/main/java/com/github/pig/gateway/filter/ErrorHandlerFilter.java @@ -0,0 +1,52 @@ +package com.github.pig.gateway.filter; + +import com.alibaba.fastjson.JSONObject; +import com.github.pig.common.util.R; +import com.github.pig.gateway.service.LogSendService; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ERROR_TYPE; +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER; + +/** + * @author lengleng + * @date 2017-12-25 17:53:38 + * 网关统一异常处理 + */ +@Component +public class ErrorHandlerFilter extends ZuulFilter { + private static final Logger logger = LoggerFactory.getLogger(ValidateCodeFilter.class); + + @Autowired + private LogSendService logSendService; + + @Override + public String filterType() { + return ERROR_TYPE; + } + + @Override + public int filterOrder() { + return SEND_RESPONSE_FILTER_ORDER + 1; + } + + @Override + public boolean shouldFilter() { + RequestContext requestContext = RequestContext.getCurrentContext(); + return requestContext.getThrowable() != null; + } + + @Override + public Object run() { + RequestContext requestContext = RequestContext.getCurrentContext(); + logSendService.send(requestContext); + return null; + } + +} diff --git a/pig-gateway/src/main/java/com/github/pig/gateway/filter/LoggerFilter.java b/pig-gateway/src/main/java/com/github/pig/gateway/filter/LoggerFilter.java index b6ecaf8d..923259a7 100644 --- a/pig-gateway/src/main/java/com/github/pig/gateway/filter/LoggerFilter.java +++ b/pig-gateway/src/main/java/com/github/pig/gateway/filter/LoggerFilter.java @@ -19,7 +19,6 @@ import static org.springframework.cloud.netflix.zuul.filters.support.FilterConst */ @Component public class LoggerFilter extends ZuulFilter { - private static final String KEY_USER = "user"; @Autowired private LogSendService logSendService; diff --git a/pig-gateway/src/main/java/com/github/pig/gateway/service/LogSendService.java b/pig-gateway/src/main/java/com/github/pig/gateway/service/LogSendService.java index 95280960..e397f930 100644 --- a/pig-gateway/src/main/java/com/github/pig/gateway/service/LogSendService.java +++ b/pig-gateway/src/main/java/com/github/pig/gateway/service/LogSendService.java @@ -9,7 +9,8 @@ import com.netflix.zuul.context.RequestContext; public interface LogSendService { /** * 往消息通道发消息 - * @param requestContext + * + * @param requestContext requestContext */ void send(RequestContext requestContext); } diff --git a/pig-gateway/src/main/java/com/github/pig/gateway/service/impl/LogSendServiceImpl.java b/pig-gateway/src/main/java/com/github/pig/gateway/service/impl/LogSendServiceImpl.java index e8de3e2c..8323b46b 100644 --- a/pig-gateway/src/main/java/com/github/pig/gateway/service/impl/LogSendServiceImpl.java +++ b/pig-gateway/src/main/java/com/github/pig/gateway/service/impl/LogSendServiceImpl.java @@ -1,14 +1,18 @@ package com.github.pig.gateway.service.impl; +import com.alibaba.fastjson.JSONObject; import com.github.pig.common.constant.CommonConstant; import com.github.pig.common.entity.SysLog; import com.github.pig.common.util.UserUtils; +import com.github.pig.common.vo.ErrorPojo; import com.github.pig.common.vo.LogVo; import com.github.pig.gateway.service.LogSendService; import com.netflix.zuul.context.RequestContext; import com.xiaoleilu.hutool.http.HttpUtil; +import com.xiaoleilu.hutool.io.IoUtil; import com.xiaoleilu.hutool.util.URLUtil; import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.AmqpTemplate; @@ -16,6 +20,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; /** * @author lengleng @@ -28,12 +36,20 @@ public class LogSendServiceImpl implements LogSendService { @Autowired private AmqpTemplate rabbitTemplate; + /** + * 1. 获取 requestContext 中的请求信息 + * 2. 如果返回状态不是OK,则获取返回信息中的错误信息 + * 3. 发送到MQ + * + * @param requestContext 上下文对象 + */ @Override public void send(RequestContext requestContext) { HttpServletRequest request = requestContext.getRequest(); String requestUri = request.getRequestURI(); String method = request.getMethod(); SysLog log = new SysLog(); + log.setType(CommonConstant.STATUS_NORMAL); log.setRemoteAddr(HttpUtil.getClientIP(request)); log.setRequestUri(URLUtil.getPath(requestUri)); log.setMethod(method); @@ -42,16 +58,48 @@ public class LogSendServiceImpl implements LogSendService { log.setCreateBy(UserUtils.getUserName(request)); Long startTime = (Long) requestContext.get("startTime"); log.setTime(System.currentTimeMillis() - startTime); + + //正常发送服务异常解析 + if (requestContext.getResponseStatusCode() != HttpStatus.SC_OK) { + InputStream inputStream = requestContext.getResponseDataStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream stream1 = null; + InputStream stream2 = null; + byte[] buffer = IoUtil.readBytes(inputStream); + try { + baos.write(buffer); + baos.flush(); + stream1 = new ByteArrayInputStream(baos.toByteArray()); + stream2 = new ByteArrayInputStream(baos.toByteArray()); + String resp = IoUtil.read(stream1, CommonConstant.UTF8); + ErrorPojo error = JSONObject.parseObject(resp, ErrorPojo.class); + log.setType(CommonConstant.STATUS_LOCK); + log.setException(error.getMessage()); + requestContext.setResponseDataStream(stream2); + } catch (IOException e) { + logger.error("响应流解析异常:", e); + throw new RuntimeException(e); + } finally { + IoUtil.close(stream1); + IoUtil.close(baos); + IoUtil.close(inputStream); + } + + } + + //网关内部异常 + Throwable throwable = requestContext.getThrowable(); + if (throwable != null) { + logger.error("网关异常", throwable); + log.setException(throwable.getMessage()); + } + + //保存发往MQ(只保存授权) LogVo logVo = new LogVo(); logVo.setSysLog(log); - //解析用户名的事情异步到rabbit消费中处理 if (StringUtils.isNotEmpty(request.getHeader(CommonConstant.REQ_HEADER))) { logVo.setToken(request.getHeader(CommonConstant.REQ_HEADER)); - } - try { rabbitTemplate.convertAndSend(CommonConstant.LOG_QUEUE, logVo); - }catch (Exception e) { - logger.error("MQ发送日志异常,异常信息:"+e.getMessage()); } } }