0%

Golang的Echo框架中,上下文echo.Context是一个接口,可以通过它重写默认的Context.JSON方法来自定义返回格式

首先定义一下接口的格式

type CommonResponse struct {
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}
阅读全文 »

对于前后端分离的项目,采用统一的返回格式可以有效减少前后端开发人员的交流成本,对于Spring MVC可以利用切面无侵入地、优雅地实现这一点。

Spring MVC提供了AbstractMappingJacksonResponseBodyAdvice抽象类对返回的JSON做二次处理

首先定义返回结构

阅读全文 »

前言

通常我们用Cloudflare WARP通过替换VPS的双栈或单栈网络来通过获得所谓“原生IP”,从而解锁Netflex等流媒体,而如果直接替换掉双栈网络会导致VPS失联,即使通过修改路由表正常使用也会影响到Docker等应用的NAT。实际上我们只需要让Xray的流量走WARP接口出去就行了,outbounds配置提供了sendThrough用来指定出口IP,streamSettings.sockopt.mark用来设置fwmark。我之前直接指定为WARP的IP发现并不行,收不到回包(实际上如果直接指定接口名就正常使用了,可惜不支持)。在翻Xray的文档时才发现还需要配置一下路由表才行。

使用sendThrough

阅读全文 »

通常我们会通过spring的异常处理器来自定义响应格式,即通过@RestControllerAdvice来实现,但是如果只是为了自定义一个返回格式的话有更好的选择,那就是自定义ErrorController,所有未被处理的异常都会被它处理,@RestControllerAdvice也被视为异常处理,即被@RestControllerAdvice处理的异常将不会到达这里,直接上代码,以Kotlin为例

@RestController
@RequestMapping("/error")
class GlobalErrorController : ErrorController {

    @Autowired
    lateinit var errorAttributes: ErrorAttributes

    @GetMapping
    fun error(request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        val ex: Throwable? = errorAttributes.getError(ServletWebRequest(request))
        val status = getStatus(request)
        return ResponseEntity.status(status)
            .body(ErrorResponse(status = status.name, message = ex?.localizedMessage ?: ""))
    }

    private fun getStatus(request: HttpServletRequest): HttpStatus {
        val statusCode = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)

        if (statusCode !is Int) {
            return HttpStatus.INTERNAL_SERVER_ERROR
        }

        return try {
            HttpStatus.valueOf(statusCode)
        } catch (e: Exception) {
            HttpStatus.INTERNAL_SERVER_ERROR
        }
    }
}
  • 这里注入了一个ErrorAttributes类型的bean,它包含了请求上下文的错误信息,通过getError方法可以获取到异常类

  • 匹配到路由/error的方法的返回值会作为响应发送到客户端,当然这个路由是可以自定义的

阅读全文 »

实现类似于zsh和fish的命令高亮和提示效果

Set-PSReadLineOption -PredictionSource History
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineOption -Colors @{ InlinePrediction = "#666666" }
Set-PSReadLineOption -BellStyle none
Set-PSReadLineOption -HistorySearchCursorMovesToEnd

直接上代码

open class BaseController<T : BaseEntity>(val baseService: BaseService<T>) {

    @Transactional
    @AuthRequired
    @PatchMapping("/{id}")
    open fun updateById(@PathVariable("id") id: Long, @RequestBody entity: T): ResponseEntity<T> {
        entity.id = id
        return ResponseEntity.ok(baseService.updateById(entity))
    }

}

访问controller时出现NullPointerException,此时baseService为null

阅读全文 »

在尝试用kotlin写springboot项目时发现springboot的kotlin项目模板的注解处理器没生效,结果就是自定义的配置类在idea中没有语法提示,且有一堆黄线警告,解决方法就是用kapt进行注解处理
在build.gradle.kts加入

plugins {
    ...
    kotlin("kapt") version "1.4.20"
}

dependencies {
    ...
    kapt("org.springframework.boot:spring-boot-configuration-processor")
}

重新构建,这样就能正确生成spring-configuration-metadata.json

阅读全文 »

在MySQL中,当使用timestamp作为储存时间的类型时,其读写都与sessiontime_zone有关。当没有显式指定时,当前session的time_zone会继承全局设置

  • 当写入时,会根据当前session的time_zone转换成UTC时间,将其时间戳进行储存
  • 当读取时,会将UTC时间戳转换为session所设置的time_zone所对应的时间

根据其他资料在连接字符串中添加参数serverTimezone

阅读全文 »