目录
1 设置配置文件路径和文件名
2 设置扫描的基础包
3 使用log4j2
4 单元测试
5 FreeMarker配置和使用
6 整合MyBatis + MySql
7 添加拦截器
8 RestTemplate使用HTTPS通信(双向认证)
1 设置配置文件路径和文件名
需要在启动前进行配置:
@SpringBootApplication
public class Main
{
public static void main(String[] args)
{
SpringApplication application = new SpringApplication(Main.class);
Map defaultMap = new HashMap();
defaultMap.put("spring.config.location", "classpath:/conf/");
defaultMap.put("spring.config.name", "kysvc");
application.setDefaultProperties(defaultMap);
application.run(args);
}
}
2 设置扫描的基础包
在启动类前添加以下注解即可
@ComponentScan(basePackages={包名})
3 使用log4j2
需要要将默认的logging配置关闭,并加入log4j2的依赖
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-logging
${springboot.version}
org.springframework.boot
spring-boot-starter-log4j2
${springboot.version}
之后在设置中指定配置文件地址,例如,配置文件为main/resources/conf文件夹下的log4j2.xml,则需要如下配置:
logging.config=classpath:conf/log4j2.xml
4 单元测试
添加依赖,注意junit版本必须在4以上
org.springframework.boot
spring-boot-starter-test
${springboot.version}
test
junit
junit
4.12
test
SpringBoot 1.4版本起,单元测试的设置有了一些变化,原来的@SpringApplicationConfiguration注解被废弃,改为使用@SpringBootTest注解[1]
在单元测试时,可通过使用@TestPropertySource注解来指定测试用的配置文件路径[5]。
单元测试范例:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Main.class)
@WebAppConfiguration
@TestPropertySource(locations="classpath:conf/test.properties")
public class UserCtrlTest
{
private MockMvc mvc;
private static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
@Before
public void setup()
{
mvc = MockMvcBuilders.standaloneSetup(new UserCtrl()).build();
}
@Test
public void sampleTest() throws Exception
{
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("/user/test").accept(MediaType.APPLICATION_JSON)).andReturn();
int status = result.getResponse().getStatus();
Assert.assertTrue("错误,正确的返回值为200", status == 200);
String content = result.getResponse().getContentAsString();
Assert.assertTrue("数据不一致", "test123".equals(content));
}
@Test
public void userInfoTest() throws Exception
{
String name = "kevin";
String idcard = "420102199901011234";
String tel = "13700000000";
User user = new User(name, idcard, tel);
String uri = "/user/" + name + "/" + idcard + "/" + tel;
MvcResult result = mvc.perform(MockMvcRequestBuilders.get(uri).accept(MediaType.APPLICATION_JSON)).andReturn();
int status = result.getResponse().getStatus();
Assert.assertEquals(200, status);
String userStr = result.getResponse().getContentAsString();
Assert.assertEquals(GSON.toJson(user), userStr);
}
}
5 FreeMarker配置和使用
添加依赖:
org.springframework.boot
spring-boot-starter-freemarker
${springboot.version}
添加配置:
#Freemarker
spring.freemarker.template-loader-path=classpath:pages/
spring.freemarker.suffix=.html
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
上面的配置将模板路径指定到了pages文件夹下,并将模板后缀设置为了html(默认为ftl)
模板范例:
亲爱的${toUserName},你好!
${message}
祝:开心!
${fromUserName}
${time?date}
注意:为页面控制器添加注解时,要使用@Controller而非@RestController !
页面控制范例:
@Controller
public class PageCtrl
{
@RequestMapping("/hello/{name}")
public String hello(@PathVariable("name") String name, ModelMap model)
{
model.addAttribute("time", new Date());
model.addAttribute("message", "今天的风儿有些喧嚣呢。");
model.addAttribute("toUserName", name);
model.addAttribute("fromUserName", "Kevin Yang");
return "hello";
}
}
6 整合MyBatis + MySql
添加依赖:
3.3.0
1.3.0
5.1.40
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis-spring.version}
mysql
mysql-connector-java
${mysql-connector.version}
在启动类前添加注解设置需要扫描的mapper包
@MapperScan(basePackages={"com.ky.tests.*.mapper"})
在配置文件中配置jdbc
#JDBC
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/ky_time_log?useUnicode=true&autoReconnect=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
注:有关DataSource的拓展设置
在官方默认的文档[0]中,没有记录一些拓展的配置,例如包括maxWait、maxActive等连接池相关的配置,这些配置都通过代理模式实现在DataSourceProxy这个类中,在配置文件中直接进行相应的配置即可,例如:
spring.datasource.maxActive=5
spring.datasource.maxWait=60000
具体原理参考:Spring-Boot: How do I set JDBC pool properties like maximum number of connections?
注意:如果使用tomcat连接池以外的连接池,可能需要其他连接池定制的设置
其余设置和接口实现与原spring mvc + mybatis相同
7 添加拦截器
首先实现一个拦截器类,重载HandlerInterceptorAdapter类,或实现HandlerInterceptor接口:
public class UserInterceptor extends HandlerInterceptorAdapter
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
String auth = request.getParameter("auth");
if("kevin".equals(auth))
{
return true;
}
else
{
throw new AuthFailure("认证失败", null);
}
}
}
然后借助spring boot的自动配置机制,注册实现的拦截器:
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter
{
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(new UserInterceptor());
}
}
注意:根据官方文档说明,在使用了自动配置的注解重载WebMvcConfigurerAdapter后,会与@EnableWebMvc注解有一定冲突,详见spring boot adding http request interceptors
8 RestTemplate使用HTTPS通信(双向认证)
首先生成服务端和客户端的密钥库和信任库,导出各自的证书,并互相添加到对方的信任库中
服务端配置:
server.ssl.enabled=true
server.ssl.key-store=classpath:cert/kysvc.p12
server.ssl.key-store-password=cking123
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=kysvc
server.ssl.trust-store=classpath:cert/kytrust.jks
server.ssl.trust-store-password=cking123
server.ssl.trust-store-type=jks
server.ssl.client-auth=NEED
客户端配置和实现:
参考RestTemplate实践,在客户端实现一个自定义SSL配置类,并在其中定义好生成ClientHttpRequestFactory所需的Bean:
@Configuration
public class SSLConfiguration
{
@Bean
public RestOperations restOperations(ClientHttpRequestFactory clientHttpRequestFactory) throws Exception
{
return new RestTemplate(clientHttpRequestFactory);
}
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient)
{
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
private KeyStore _parseKeyStore(String keystorePath, String passwd) throws Exception
{
String keyStoreType = "jks";
if(keystorePath.endsWith(".p12"))
{
keyStoreType = "pkcs12";
}
KeyStore keystore = KeyStore.getInstance(keyStoreType);
if(keystorePath.startsWith("classpath:"))
{
keystorePath = ClassLoader.getSystemResource("").getFile() + keystorePath.substring(keystorePath.indexOf(":") + 1);
}
FileInputStream instream = new FileInputStream(new File(keystorePath));
try
{
keystore.load(instream, passwd.toCharArray());
}
finally
{
instream.close();
}
return keystore;
}
@Bean
public HttpClient httpClient(@Value("${https.client.keystore.file}") String keyStoreFile,
@Value("${https.client.keystore.pass}") String keyPass,
@Value("${https.client.truststore.file}") String trustStoreFile,
@Value("${https.client.truststore.pass}") String trustPass) throws Exception
{
KeyStore keyStore = _parseKeyStore(keyStoreFile, keyPass);
KeyStore trustStore = _parseKeyStore(trustStoreFile, trustPass);
SSLContext sslcontext = SSLContexts.custom()//
.loadKeyMaterial(keyStore, keyPass.toCharArray())//
.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1.2" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
{
return new PropertySourcesPlaceholderConfigurer();
}
}
然后根据上述实现,在配置文件中添加相应配置:
#Client
https.client.keystore.file=classpath:cert/httpstest.p12
https.client.keystore.pass=cking123
https.client.truststore.file=classpath:cert/truststore.jks
https.client.truststore.pass=cking123
配置好后即可借助RestTemplate对服务端进行https调用:
@RestController
@RequestMapping(path = "/invoke")
public class SvcInvoker
{
@Autowired
ClientHttpRequestFactory factory; //这个资源在上面的SSLConfiguration中已有定义
@RequestMapping(path = "/timelog")
public @ResponseBody String getTimeLogs()
{
RestTemplate involker = new RestTemplate(factory);
return involker.getForEntity("https://172.17.99.187:8443/timelog/all", String.class).getBody();
}
}
参考链接
[0] Appendix A. Common application properties(官方配置范例)
[1] Spring Boot 1.4 单元测试
[2] Spring Boot-构建一个复杂的RESTful API及单元测试
[3] RESTful API 设计指南
[4] Spring boot 使用FreeMarker模板
[5] Override default Spring-Boot application.properties settings in Junit Test
[6] Testing improvements in Spring Boot 1.4
[7] Spring Boot 整合 MyBatis
[8] spring boot adding http request interceptors
[9] Spring MVC HandlerInterceptor Annotation Example with WebMvcConfigurerAdapter
[10] RestTemplate实践