spring boot学习笔记
官方地址:https://spring.io/projects
1. 从hello world 开始
1.1 maven 依赖
org.springframework.boot
spring-boot-starter-parent
2.0.2.RELEASE
org.springframework.boot
spring-boot-starter-web
1.2 编写启动程序
1.2.1 方式一
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Spring boot "hello word"
* @author vchar fred
* @version 1.0
* @date 2018/6/12 15:42
*/
@RestController//相当于Controller+ResponseBody;即自动是ajax的请求
@EnableAutoConfiguration//spring 会自动装配相关的配置,这个是必须有的
public class SpringBootHello {
@RequestMapping("/")
public String home(){
return "hello word!";
}
public static void main(String[] args) throws Exception{
SpringApplication.run(SpringBootHello.class, args);
}
}
运行main方法,在浏览器中访问:http://localhost:8080/ 即可看到hello word
打jar包运行的方法:添加如下maven插件依赖
org.springframework.boot
spring-boot-maven-plugin
运行maven的 package命令;然后运行 java -jar xxx.jar
1.2.2 方式二
@SpringBootApplication//这个注解包含了EnableAutoConfiguration;更多的配置可以查看源码
@RestController//相当于Controller+ResponseBody;即自动是ajax的请求
public class SpringBootHello {
@RequestMapping("/")
public String home(){
return "hello word!";
}
public static void main(String[] args) throws Exception{
SpringApplication.run(SpringBootHello.class, args);
}
}
@SpringBootApplication 注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
//排除自启动项
Class[] exclude() default {};
//排除自动启动的beanName
String[] excludeName() default {};
//扫描包
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
//扫描类
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class[] scanBasePackageClasses() default {};
}
2. log日志
来源:https://blog.csdn.net/king_is_everyone/article/details/53074006
SpringBoot默认是采用logback进行日志处理、Logback是由log4j创始人设计的又一个开源日志组件
logback当前分成三个模块:logback-core,logback- classic和logback-access
。logback-core是其它两个模块的基础模块
2.1 logback.xml详情
spring-boot-demo-log
%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg %n
DEBUG
${LOG_PATH}/${APP_ID}/access.log
${LOG_PATH}/${APP_ID}/access.log.%d{yyyy-MM-dd}.zip
10
%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n
DEBUG
ACCEPT
DENY
${LOG_PATH}/${APP_ID}/access_debug.log
${LOG_PATH}/${APP_ID}/access_debug.log.%d{yyyy-MM-dd}.zip
10
%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n
INFO
ACCEPT
DENY
${LOG_PATH}/${APP_ID}/access_info.log
${LOG_PATH}/${APP_ID}/access_info.log.%d{yyyy-MM-dd}.zip
10
%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n
WARN
ACCEPT
DENY
${LOG_PATH}/${APP_ID}/access_warn.log
${LOG_PATH}/${APP_ID}/access_warn.log.%d{yyyy-MM-dd}.zip
10
%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n
ERROR
ACCEPT
DENY
${LOG_PATH}/${APP_ID}/access_error.log
${LOG_PATH}/${APP_ID}/access_error.log.%d{yyyy-MM-dd}.zip
10
%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n
0
64
0
64
0
64
0
64
0
64
0
64
3.统一异常处理
来源:https://blog.csdn.net/king_is_everyone/article/details/53080851
3.1 spring boot 自带的统一异常处理,重新配置异常地址和页面
SpringBoot在页面发生异常的时候会自动把请求转到/error; SpringBoot内置了一个BasicErrorController对异常进行统一的处理,
这个错误的地址是可以重新配置的。
在resources
目录下创建一个application.yaml配置文件;写入如下配置
server:
#访问端口号
port: 8082
error:
#设置错误路径
path: /test/error
开始编写测试程序
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 测试异常
*
* @author vchar fred
* @version 1.0
* @date 2018/6/13 11:17
*/
@SpringBootApplication
@Controller
public class TestExceptionController {
@RequestMapping(value = "/ajax")
@ResponseBody
public String ajaxRequestExceptionTest(int nu){
//传入参数为0时抛出异常
int num = 1/nu;
return "this ok "+ num;
}
@RequestMapping(value = "/htmls")
public String htmlRequestExceptionTest(int nu){
//传入参数为0时抛出异常
int num = 1/nu;
return "index";
}
//启动
public static void main(String[] args) throws Exception{
SpringApplication.run(TestExceptionController.class);
}
}
在resources
目录下创建templates目录(这个是默认放置模版文件的目录),并分别创建error.ftl和index.ftl 文件。error.ftl文件用于替换spring boot原有的错误页面,index.ftl用于测试页面
由于用到了freemarker,需要添加maven依赖
org.springframework.boot
spring-boot-starter-freemarker
启动后开始测试
#测试是否可正常访问
http://127.0.0.1:8082/htmls?nu=1
#测试异常页面
http://127.0.0.1:8082/htmls?nu=0
#ajax请求返回的错误提示
{
"timestamp": "2018-06-13T03:55:51.587+0000",
"status": 500,
"error": "Internal Server Error",
"message": "/ by zero",
"path": "/ajax"
}
3.2 通用Exception处理
通过使用@ControllerAdvice来进行统一异常处理,@ExceptionHandler(value = Exception.class)来指定捕获的异常
下面针对两种异常进行了特殊处理分别返回页面和json数据,使用这种方式有个局限,无法根据不同的头部返回不同的数据格式,而且无法针对404、403等多种状态进行处理
//异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
@ExceptionHandler(value = CustomException.class)
@ResponseBody
public ResponseEntity defaultErrorHandler(HttpServletRequest req, CustomException e) throws Exception {
return ResponseEntity.ok("ok");
}
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}
//自定义异常
public class CustomException extends Exception {
CustomException(String errorMsg){
super(errorMsg);
}
}
//测试路由
@RequestMapping(value = "/coustom")
public String coustomExceptionTest() throws CustomException {
customExce();
return "index";
}
private void customExce() throws CustomException {
throw new CustomException("自定义异常");
}
3.3 自定义BasicErrorController 错误处理
在初始介绍哪里提到了BasicErrorController,这个是SpringBoot的默认错误处理,也是一种全局处理方式。咱们可以模仿这种处理方式自定义自己的全局错误处理
下面定义了一个自己的BasicErrorController,可以根据自己的需求自定义对应的错误处理。
@ResponseStatus 注解的异常类会被ResponseStatusExceptionResolver 解析
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义异常controller
*
* @author vchar fred
* @version 1.0
* @date 2018/6/13 14:25
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
public BasicErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes);
}
private static final Logger log = LoggerFactory.getLogger(BasicErrorController.class);
@Value("${server.error.path:${error.path:/error}}")
private static String errorPath = "/error";
/**
* 500 错误
* @param request
* @param response
* @param ex
* @return
* @throws Exception
*/
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ModelAndView serverError(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
return handleViewError(ex.getMessage(), "500", "error/500");
}
/**
* 404错误
* @param request
* @param response
* @param ex
* @return
* @throws Exception
*/
@ResponseStatus(code = HttpStatus.NOT_FOUND)
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity
定义文件结构如下:
4. spring boot中使用redis
application.yaml配置文件中添加redis如下配置
spring:
rdeis:
host: 127.0.0.1
port: 6379
timeout: 3000
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-total: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait-millis: -1
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0
加入需要的依赖包
org.springframework.boot
spring-boot-starter-data-redis
注:网上其他有很多教程说引入的是下面这个包
org.springframework.boot
spring-boot-starter-redis
但是我在引入时发现当前这个版本中这个包已经无法下载了。
4.1 redis 配置方式1,使用默认的
因为上面依赖了spring-boot-starter-data-redis,可以使用默认的 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
类加载properties文件的配置。它的源码如下:
@Configuration
protected static class RedisConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate
使用方法
@RestController
public class StartServe {
@Autowired
private StringRedisTemplate template;
@Autowired
private RedisTemplate redisTemplate;
@RequestMapping("/redis")
public String redisTest(){
//这两个的是不一样的。因为RedisTemplate 默认会将对象使用JdkSerializationRedisSerializer进行序列化
redisTemplate.opsForValue().set("test", "123456");
template.opsForValue().set("test", "abcdef");
return template.opsForValue().get("test")+"---|||---"+redisTemplate.opsForValue().get("test");
}
}
4.2 redis 配置方式2,自己手动配置
4.2.1 redis的单机版连接池配置
需要加入额外的jar包:
redis.clients
jedis
2.9.0
编写相关代码:
-
单机版
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import redis.clients.jedis.JedisPoolConfig; /** *
redis 配置
* * @author vchar fred * @version 1.0 * @date 2018/6/13 18:05 */ @Configuration public class RedisConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; //@Value("${spring.redis.password}") //private String password; @Value("${spring.redis.pool.max-idle}") private int maxIdle; @Value("${spring.redis.pool.min-idle}") private int minIdle; @Value("${spring.redis.pool.max-total}") private int maxTotal; @Value("${spring.redis.pool.max-wait-millis}") private int maxWaitMillis; /** * 连接设置 * @return 返回连接工厂 */ @Bean(name = "jedisConnectionFactory") public JedisConnectionFactory getJedisConnectionFactory(JedisPoolConfig jedisPoolConfig){ JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName(host); factory.setPort(port); //factory.setPassword("");//设置认证密码 //factory.setDatabase();//设置库 factory.setTimeout(timeout); factory.setUsePool(true); factory.setPoolConfig(jedisPoolConfig); return factory; } /** * 连接池设置 * @return 返回连接池配置 */ @Bean(name = "jedisPoolConfig") public JedisPoolConfig getJedisPoolConfig(){ JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(maxTotal); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); jedisPoolConfig.setMinIdle(minIdle); return jedisPoolConfig; } /** * RedisTemplate * @param jedisConnectionFactory JedisConnectionFactory * @return */ @Bean public RedisTemplate redisTemplate(JedisConnectionFactory jedisConnectionFactory){ RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(jedisConnectionFactory); //key序列化方式;但是如果方法上有Long等非String类型的话,会报类型转换错误; RedisSerializerredisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息; redisTemplate.setKeySerializer(redisSerializer); redisTemplate.setHashKeySerializer(redisSerializer); //key序列化方式;但是如果方法上有Long等非String类型的话,会报类型转换错误; redisTemplate.setValueSerializer(redisSerializer); redisTemplate.setHashValueSerializer(redisSerializer); redisTemplate.afterPropertiesSet(); //查看 StringRedisTemplate 的初始化源码,你会发现其实它和上面一样做了的key和value的序列化设置 return redisTemplate; } /** * StringRedisTemplate * @param jedisConnectionFactory JedisConnectionFactory * @return StringRedisTemplate */ @Bean public StringRedisTemplate stringRedisTemplate(JedisConnectionFactory jedisConnectionFactory){ StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(jedisConnectionFactory); return stringRedisTemplate; } } -
集群版
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import java.util.HashSet; import java.util.Set; /** * redis集群配置 */ @Configuration //相当于以前的配置文件 public class RedisConfig { @Value("${spring.redis.cluster.nodes}") private static String clusterNodes; @Bean("jedisCluster") public JedisCluster getJedisCluster(){ String[] cNodes = clusterNodes.split(","); Set
nodes = new HashSet (); for (String node: cNodes) { String[] hp = node.split(":"); nodes.add(new HostAndPort(hp[0],Integer.parseInt(hp[1]))); } //创建redis的集群对象 return new JedisCluster(nodes); } }
使用方式同上面方式一的,这次你会发现他们的key是一样(因为序列化的方式是一样的了)。
另附一个redis配置比较完整的配置文件
来源:https://www.cnblogs.com/EasonJim/p/7805665.html
-
单机版
# REDIS(RedisProperties) # (普通集群,不使用则不用开启)在群集中执行命令时要遵循的最大重定向数目。 # spring.redis.cluster.max-redirects= # (普通集群,不使用则不用开启)以逗号分隔的“主机:端口”对列表进行引导。 # spring.redis.cluster.nodes= # 连接工厂使用的数据库索引。 spring.redis.database=0 # 连接URL,将覆盖主机,端口和密码(用户将被忽略),例如:redis://user:[email protected]:6379 spring.redis.url= # Redis服务器主机。 spring.redis.host=localhost # 登录redis服务器的密码。 spring.redis.password= # 启用SSL支持。 spring.redis.ssl=false # 池在给定时间可以分配的最大连接数。使用负值无限制。 spring.redis.pool.max-total=8 # 池中“空闲”连接的最大数量。使用负值表示无限数量的空闲连接。 spring.redis.pool.max-idle=8 # 连接分配在池被耗尽时抛出异常之前应该阻塞的最长时间量(以毫秒为单位)。使用负值可以无限期地阻止。 spring.redis.pool.max-wait-millis=-1 # 目标为保持在池中的最小空闲连接数。这个设置只有在正面的情况下才有效果。 spring.redis.pool.min-idle=0 # Redis服务器端口。 spring.redis.port=6379 # (哨兵模式,不使用则不用开启)Redis服务器的名称。 # spring.redis.sentinel.master= # (哨兵模式,不使用则不用开启)主机:端口对的逗号分隔列表。 # spring.redis.sentinel.nodes= # 以毫秒为单位的连接超时。 spring.redis.timeout=0
-
集群版,将下面这2项打开即可。
# (普通集群,不使用则不用开启)在群集中执行命令时要遵循的最大重定向数目。 spring.redis.cluster.max-redirects= # (普通集群,不使用则不用开启)以逗号分隔的“主机:端口”对列表进行引导。 spring.redis.cluster.nodes=127.0.0.1:1001,127.0.0.1:1002
注意:一旦开启了集群模式,那么基于单机的配置就会覆盖。
使用到的注解说明
注解 | 说明 |
---|---|
@EnableAutoConfiguration | spring会自动的猜测你需要的那些配置,智能的帮助你去扫描配置 |