springboot中@ControllerAdvice异常处理

代码如下

 

 

@ControllerAdvice
open class ExceptionHandler : ResponseBodyAdvice<Any> {

    private val LOGGER = LoggerFactory.getLogger(ExceptionHandler::class.java)

    @Autowired
    lateinit var sysAdminRequestLogService: SysAdminRequestLogService

    @Autowired
    private lateinit var serverProperties: ServerProperties

    @Autowired
    private lateinit var jsonConverter: MappingJackson2HttpMessageConverter

    private val EXCEPTION_TAG = "exception"
    private val ERROR_CODE_TAG = "error_code"
    private val OPERATOR_ID = "operator_id"
    private val TIME_ZONE = "user_timezone"

    override fun beforeBodyWrite(body: Any, returnType: MethodParameter?, selectedContentType: MediaType?,
                                 selectedConverterType: Class<out HttpMessageConverter<*>>?, request: ServerHttpRequest?, response: ServerHttpResponse?): Any? {
        if (!request!!.uri.toString().contains("swagger") && request.uri.toString().contains("api-docs")) {
            LOGGER.trace(" uri[${request.uri}], and result[$body]")
            return body
        }
        val timeZone = parseTimezone(request)
        jsonConverter.objectMapper.setTimeZone(timeZone)

        val result = jsonConverter.objectMapper.writeValueAsString(body)

        val httpLogMessage = constructHttpLogMessage((request as ServletServerHttpRequest).servletRequest, result)
        httpLogMessage?.let {
            val httpRequestLog = constructHttpRequestLog(it)
            sysAdminRequestLogService.save(httpRequestLog)
        }

        return JSONObject.parseObject(result, body.javaClass)

    }

    override fun supports(returnType: MethodParameter?, converterType: Class<out HttpMessageConverter<*>>?): Boolean {
        return true
    }

    @ExceptionHandler(MethodArgumentNotValidException::class)
    @ResponseBody
    @Throws(Exception::class)
    fun parameterInvalidException(e: MethodArgumentNotValidException, request: HttpServletRequest): BizResponse<Any> {
        LOGGER.error(" parameterInvalidException :", e)
        val response = BizResponse<Any>(ErrorCode.PARAM_ERROR.code, ErrorCode.PARAM_ERROR.msg)

        try {
            val propertyBindResult: BeanPropertyBindingResult = e.bindingResult as BeanPropertyBindingResult
            if (propertyBindResult.hasErrors()) {
                var sbf = StringBuffer()
                propertyBindResult.allErrors.forEach {
                    sbf.append(it.defaultMessage).append(";")
                }
                response.msg = sbf.toString()
            }
            return response
        } catch (e: Exception) {
            request.setAttribute(EXCEPTION_TAG, getStackTrace(e))
            request.setAttribute(ERROR_CODE_TAG, response.code)
            LOGGER.error(" parameterInvalidException url[${request.requestURL}]", e)
            return response
        }
    }

    @ExceptionHandler(Exception::class)
    @ResponseBody
    @Throws(Exception::class)
    fun sysException(e: Exception, request: HttpServletRequest): BizResponse<Any> {

        val response = BizResponse<Any>(ErrorCode.SYS_INTERNAL_ERROR.code, ErrorCode.SYS_INTERNAL_ERROR.msg)
        request.setAttribute(EXCEPTION_TAG, getStackTrace(e))
        request.setAttribute(ERROR_CODE_TAG, response.code)

        LOGGER.error("Exception requestUrl[${request.requestURL}] ", e)
        return response
    }

    @ExceptionHandler(BizException::class)
    @ResponseBody
    @Throws(RuntimeException::class)
    fun bizeException(e: BizException, request: HttpServletRequest): BizResponse<Any> {
        val response = BizResponse<Any>(e.code, e.msg)
        request.setAttribute(ERROR_CODE_TAG, response.code)
        request.setAttribute(EXCEPTION_TAG, getStackTrace(e))
        LOGGER.error("BizException requestUrl[${request.requestURL}] ${e.code}:${e.msg}")
        return response
    }

    /**
     * 缺失@RequestParam参数
     */
    @ExceptionHandler(MissingServletRequestParameterException::class)
    @ResponseBody
    @Throws(RuntimeException::class)
    fun bizeException(e: MissingServletRequestParameterException): BizResponse<Any> {
        val response = BizResponse<Any>(ErrorCode.PARAM_INCOMPLETE_ERROR.code, ErrorCode.PARAM_INCOMPLETE_ERROR.msg)
        return response
    }

    private fun constructHttpRequestLog(message: HttpLogMessage): SysAdminRequestLog {

        val sysAdminRequestLog = SysAdminRequestLog()

        sysAdminRequestLog.operatorId = message.operatorId
        sysAdminRequestLog.errorCode = message.errorCode
        sysAdminRequestLog.method = message.method
        sysAdminRequestLog.requestIp = message.requestIp
        sysAdminRequestLog.module = message.module
        sysAdminRequestLog.requestParmas = message.requestParmas
        sysAdminRequestLog.requestUri = message.requestUri
        sysAdminRequestLog.requestUrl = message.requestUrl
        sysAdminRequestLog.requestUuid = message.requestUuid
        sysAdminRequestLog.response = message.response
        sysAdminRequestLog.stackTrace = message.stackTrace
        sysAdminRequestLog.timestamp = message.timestamp
        sysAdminRequestLog.responseTime = (System.currentTimeMillis() - message.timestamp!!)

        return sysAdminRequestLog
    }

    private fun constructHttpLogMessage(request: HttpServletRequest, response: String?): HttpLogMessage? {

        val requestURI = request.requestURL.toString()
        LOGGER.trace(" requestURI:[$requestURI]")

        val httpLogMessage = HttpLogMessage()
        httpLogMessage.operatorId = getOperatorId(request)
        httpLogMessage.errorCode = getErrorCode(request)
        httpLogMessage.method = request.method
        httpLogMessage.requestIp = getRealRemoteIpAddress(request)
        httpLogMessage.module = serverProperties.displayName
        httpLogMessage.requestParmas = getRequestBody(request)
        httpLogMessage.requestUri = request.requestURI
        httpLogMessage.requestUrl = request.requestURL.toString()
        httpLogMessage.requestUuid = getRequestUuid(request)
        httpLogMessage.response = response
        httpLogMessage.stackTrace = getStackTrace(request)
        httpLogMessage.timestamp = System.currentTimeMillis()
        httpLogMessage.responseTime = (System.currentTimeMillis() - httpLogMessage.timestamp!!)

        return httpLogMessage
    }

    private fun getStackTrace(request: HttpServletRequest): String? {
        return request.getAttribute(EXCEPTION_TAG)?.toString()
    }

    private fun getStackTrace(e: Exception): String {

        val stringBuffer = StringBuffer(e.toString() + "\n")
        val messages = e.stackTrace
        messages.forEach {
            stringBuffer.append("\t $it \n")
        }

        return stringBuffer.toString()
    }

    private fun getRequestUuid(request: HttpServletRequest): String? {
        return request.getHeader(RequestType.REQUEST_UUID_TAG)
    }

    private fun getRequestBody(request: HttpServletRequest): String {

        val stringBuffer = StringBuffer()

        try {
            val buf: ByteArray = kotlin.ByteArray(1024 * 100)
            val inputStream = request.inputStream
            var len = 0
            while (inputStream.read(buf).apply { len = this } != -1) {
                stringBuffer.append(String(buf, 0, len))
            }

            if (stringBuffer.isEmpty() || stringBuffer.toString() == "") {
                return ""
            }

            val json = JSONObject.parseObject(stringBuffer.toString())
            if (json.containsKey("password")) {
                json["password"] = "*******"
            }

            return json.toString()

        } catch (e: Exception) {

            LOGGER.error(" getRequestBody exception", e)
        }

        return stringBuffer.toString()
    }

    private fun getRealRemoteIpAddress(request: HttpServletRequest): String {

        var clientIp = request.getHeader("X-Forwarded-For")
        if (null != clientIp) {
            val arr = clientIp.replace("[", "").replace("]", "").split(",")
            if (!arr.isEmpty()) {
                clientIp = arr.first()
            }
            return clientIp
        } else {
            clientIp = request.getHeader("X-Real-IP")
        }

        if (null == clientIp) {
            clientIp = request.remoteAddr
        }

        return clientIp
    }

    private fun getErrorCode(request: HttpServletRequest): Int {
        val errorCode = request.getAttribute(ERROR_CODE_TAG)?.toString()
        return errorCode?.toInt() ?: 0
    }

    private fun getOperatorId(request: HttpServletRequest): Long? {
        var operatorIdStr = request.getAttribute(OPERATOR_ID)?.toString()
        if (null == operatorIdStr || "" == operatorIdStr) {
            return null
        }
        return operatorIdStr.toLong()
    }

    private fun parseTimezone(request: ServerHttpRequest): TimeZone {

        var zone = (request as ServletServerHttpRequest).servletRequest.getHeader(TIME_ZONE)
        var timeZone = TimeZone.getDefault()

        try {
            val hour = zone.toInt()
            if (hour >= 0) {
                zone = "GMT+$hour"
            } else {
                zone = "GMT$hour"
            }

            timeZone = StringUtils.parseTimeZoneString(zone)
        } catch (e: Exception) {
        }

        return timeZone
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值