从接触springboot开始,便深深的被它的简洁性深深的折服了,精简的配置,方便的集成,使我再也不想用传统的ssm框架来搭建项目,一大堆的配置文件,维护起来很不方便,集成的时候也要费力不少。从第一次使用springboot开始,一个简单的main方法,甚至一个配置文件也不需要(当然我是指的没有任何数据交互,没有任何组件集成的情况),就可以把一个web项目启动起来,下面总结一下自从使用springboot依赖,慢慢完善的自己的一个web系统的架构,肯定不是最好的,但平时自己用着很舒服。
1. 配置信息放到数据库里边
个人比较不喜欢配置文件,因此有一个原则,配置文件能不用就不用,配置信息能少些就少些,配置内容能用代码写坚决不用xml,因此我第一个想到的就是,能不能把springboot的配置信息写到数据库里,在springboot启动的时候自动去加载,而在application.properties里边只写一个数据源。最终找到了方法:
注意图中箭头指向的两行,构造了一个properties对象,然后将这个对象放到了springboot的启动对象application中,properties是一个类似map的key-value容器,springboot可以将其中的东西当做成原来application.properties中的内容一样,因此在properties对象的内容也就相当于写在了application.properties文件中。知道了这个之后就简单了,我们将原本需要写在application.properties中的所有配置信息写在数据库中,在springboot启动的时候从数据库中读取出来放到properties对象中,然后再将这个对象set到application中即可。上图中PropertyConfig.loadProperties()方法就是进行了这样的操作,代码如下:
PropertyConfig.java
public class PropertyConfig {
/**
* 生成Properties对象
*/
public static Properties loadProperties() {
Properties properties = new Properties();
loadPropertiesFromDb(properties);
return properties;
}
/**
* 从数据库中加载配置信息
*/
private static void loadPropertiesFromDb(Properties properties) {
InputStream in = PropertyConfig.class.getClassLoader().getResourceAsStream("application.properties");
try {
properties.load(in);
} catch (Exception e) {
e.printStackTrace();
}
String profile = properties.getProperty("profile");
String driverClassName = properties.getProperty("spring.datasource.driver-class-name");
String url = properties.getProperty("spring.datasource.url");
String userName = properties.getProperty("spring.datasource.username");
String password = properties.getProperty("spring.datasource.password");
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Class.forName(driverClassName);
String tableName = "t_config_dev";
if ("pro".equals(profile)) {
tableName = "t_config_pro";
}
String sql = "select * from " + tableName;
conn = DriverManager.getConnection(url, userName, password);
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
String key = rs.getString("key");
String value = rs.getString("value");
properties.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
代码中,首先使用古老的jdbc技术,读取数据库t_config表,将表中的key-value加载到properties中,代码中profile是为了区分开发环境和生产环境,以便于确定从那张表中加载配置文件,数据库中的配置信息如下:
这样以后,application.properties中就不用再写很多的配置信息,而且,如果将这些配置信息放到数据库中之后,如果起多个应用可是公用这一张表,这样也可以做到配置信息的公用的效果,这样修改以后,配置文件中就只有数据源的信息了:
profile代表使用哪个环境,代码中可以根据这个信息来从开发表中加载配置信息还是从生产表中加载配置信息。
2. 统一返回结果
一般web项目中,大多数都是接口,以返回json数据为主,因此统一一个返回格式很必要。在本示例中,建了一个BaseController,所有的Controller都需要继承这个类,在这个BaseController中定义了成功的返回和失败的返回,在其他业务的Controller中,返回的时候,只需要return super.success(xxx)或者return super.fail(xxx, xxx)即可,例:
说到这里,返回给前台的状态码,建议也是封装成一个枚举类型,不建议直接返回200、400之类的,不方便维护也不方便查询。那么BaseController里做了什么呢?如下:
定义一个ResultInfo类,该类只有两个属性,一个是Integer类型的状态码,一个是泛型,用于成功时返回给前台的数据,和失败时返回给前台的提示信息。
3. 统一异常捕获
在上一步中的Controller代码中看到抛出了一个自定义的异常,在Controller中,属于最外层的代码了,这个时候如果有异常就不能直接抛出去了,这里再抛出去就没有人处理了,服务器只能返回给前台一个错误,用户体验不好。因此,建议所有的Controller代码都用try-catc