What

产品经理、测试人员、开发人员统一在Gitlab中管理需求bug

Why -> 为什么通过Gitlab issue管理,而不是Jira、Redmine等工具?

  1. 开发团队最终交付物为项目代码,需求bug最终都会转换为一行代码、一次MR。通过issue可以让每一步都可以溯源。
  2. Gitlab issue更轻量,markdown语法让issue更专注于内容本身
Read more »

http log

本文旨在讨论如何利用aop打印springboot http日志,包括访问日志、接口返回response,以及异常堆栈信息。

背景

为什么需要log

有过线上问题排查经历的同学都知道,日志可以给你提供最直白、最明确的信息。此外,通过对日志的收集、审计,可以对BI以及系统健壮性提供建议。尤其是新系统上线之初,系统稳定性不足,更需要日志监控。

Read more »

本文项目已发布到github,后续学习项目也会添加到此工程下,欢迎fork点赞。
https://github.com/wangyuheng/spring-boot-sample

国际化

简单来说,国际化就是让应用(app、web)适应不同的语言和地区的需要,比如根据地区选择页面展示语言。

i18n=internationalization,首末字符i和n,18为中间的字符数

原理

基于传入语言or地区标识进行判断,输出不同内容。伪代码如下:

Read more »

wikipedia的解释

弗兰兹·卡夫卡,生活于奥匈帝国统治下的捷克德语小说家,本职为保险业职员。主要作品有小说《审判》、《城堡》、《变形记》等。

kafka官网的解释

Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量分布式 发布订阅 消息系统,它可以处理消费者规模的网站中的所有动作流数据。

两个kafka有一个共同特点: 很会写

消息系统

实现低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。

Read more »

项目源码地址: github

背景

通过plantuml绘制数据库ER图,手写字段信息成本太大。需要一套DDL转换plantuml的工具。

方案

  1. 读取同目录下ddl.sql文件
  2. 基于 ; 分割建表语句
  3. 依赖 druid 进行sql解析
  4. 定义plantuml模版
  5. replaceAll替换模版内容
Read more »

背景

公司为了快速上线,几个月前通过docker镜像 kafka 部署了一台kafka-borker。Dockerfile如下

FROM wurstmeister/kafka:latest

ENV KAFKA_MESSAGE_MAX_BYTES=21474836
ENV KAFKA_AUTO_CREATE_TOPICS_ENABLE=true
ENV KAFKA_CREATE_TOPICS=test:1:1
ENV KAFKA_ZOOKEEPER_CONNECT=zk1:2181

VOLUME ["/kafka"]

随着业务的增长,单节点的kafka-broker已经成为一个潜在的可靠性隐患。所以借着N年难得一遇的停机维护,决定把kafka-broker扩容为主备集群模式,提升稳定性,并为日后的分区扩容提供可能(不停服)。

Read more »

如何搭建一个监控系统

生产环境必须是可监控的,一个对开发者黑盒的线上应用无异于灾难。一个简单的监控系统大致包含以下几部分:

  1. 采集数据
  2. 保存数据
  3. 数据可视化
  4. 监控告警

m0

Read more »

前提

微服务通过http协议进行内容传递,因为http协议自由且松散,所以有必要提供一套强有力的约定来限制接口。
服务内部实现,可以基于个人编程风格,但涉及到交互协作,必须提供风格一致的输入输出,减少开发与维护成本。

Read more »

1. 项目背景

项目地址: https://github.com/wangyuheng/Haro-CMS

最近因为换电脑整理资料的过程中,发现了自己之前写过的一些项目,现在准备拿出来升级一下,构建自己的技术体系。看着三个月前的代码,已经似曾相识了,那三年前的呢?
这个项目是用来做企业展示的简易CMS系统,后台管理员可以编辑展示内容,发布新闻;访问用户可以查看企业信息,并反馈建议。这个系统当时应该熬了几个通宵,因为5000大洋实在太吸引人。。而且还是三个人分。。。人的时间好像是越往后越值钱,现在看可能觉得不值,但还是很感谢熬夜编码的自己。
项目当时考虑了很多:分布式,前后端分离,甚至是saas化,希望根据用户反馈,或者再接到类似的项目,可以进一步完善,但是并没有什么后续。所以项目历史就是一个基于web.xml配置的spring单机应用。

1.1 依赖项目

  1. spring-boot
  2. h2
  3. gson

目前将其升级为spring-boot应用,并且为了开发演示方便,开发环境使用了H2数据库。一直觉得,项目不需要修改任何配置就能跑起来很重要。

2. 项目code

企业信息展示,分为3个module

  1. admin 管理人员编辑展示内容
  2. view 展示企业信息及新闻
  3. core 业务数据层

haro_designpng

新版spring boot已不推荐使用jsp,带来很多不便,如: 不能直接运行java, 需要使用maven spring boot 插件运行。

mvn spring-boot:run

admin 和 view 只负责业务渲染与鉴权,业务操作放在core中,方便后期进行前后端分离。
生产环境数据库使用mysql,为了方便演示,开发环境使用H2内嵌数据库。

2.1 admin

haro_adminpng

2.2 view

haro_viewpng

3 问题

之前的项目基于spring开发,采用web.xml配置。spring-boot通过约定大于配置,极大的简化了这部分工作,但是有时候又会因为不熟悉带来迷茫。明明我没有这个配置,怎么就生效了。。而且jsp又不推荐使用,所以虽然大部分是在删代码,单还是遇到了很多问题。

3.1 设置视图解析器InternalResourceViewResolver

原项目在mvc-dispatcher-servlet.xml文件中配置

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

spring-boot提供了默认配置prefix = “spring.mvc”,详情可以参看org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties类, 并在org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration类中自动注入。

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
...
        @Bean
        @ConditionalOnMissingBean
        public InternalResourceViewResolver defaultViewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix(this.mvcProperties.getView().getPrefix());
            resolver.setSuffix(this.mvcProperties.getView().getSuffix());
            return resolver;
        }
...
}

所以只需在application.properties中添加配置项

spring.mvc.view.prefix=/WEB-INF/pages/
spring.mvc.view.suffix=.jsp

3.2 静态资源请求

未实现前后端分离的项目,css、js等静态资源仍保存在项目中。spring-boot建议保存在resource/static目录下,并通过spring.resources.static-locations属性设置目录位置,并且需要制定mapping规则。

spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/

3.3 spring-boot 运行war项目

需要添加tomcat-embed依赖,并且设置servlet初始化。如果使用jsp标签,一般也需要添加jstl依赖。

    <dependencies>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- Provided -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
@SpringBootApplication
@ComponentScan(basePackages={"wang.crick.business.haro"})
public class ViewAPP extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ViewAPP.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(ViewAPP.class, args);
    }

}

需要通过spring-boot maven插件运行。

mvn spring-boot:run

3.4 自定义请求后缀匹配

旧项目中为了提高seo通过servlet-mapping指定请求路径为.html

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

spring-boot在org.springframework.boot.autoconfigure.web.ServerProperties提供了servlet相关配置,可以通过application.properties配置

server.servlet.path=*.html

但是目前希望忽略后缀,即请求index和index.html都可以路由到对应的页面,此时可以通过设置pathmatch属性实现

   /**
     * Whether to use suffix pattern match (".*") when matching patterns to requests.
     * If enabled a method mapped to "/users" also matches to "/users.*".
     */
spring.mvc.pathmatch.use-suffix-pattern=true

3.5 使用内存数据库H2

为了让程序可以“无痛”运行,在代码中使用了基于内存的H2数据库,生产环境可以考虑mysql等关系型数据库,只需修改对应的配置即可。

需要添加H2依赖,引入驱动。

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>

在配置文件application.properties中直接配置路径、驱动、以及账户信息

spring.datasource.url=jdbc:h2:mem:~/.h2/haro
spring.datasource.schema=classpath:db/schema.sql
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=root
spring.datasource.password=123456

db/schema.sql放置在resource目录下,保存了DDL以及开发环境所需数据。DDL支持情况为标准sql语句,部分工具导出的脚本需要简单修改。在程序启动过程中,会初始化执行,如果有异常,会在控制台中有详细提示。