SpringBoot一些基础常用技术
@RestController和@Controller
@RestController = @Controller + @ResponseBody
1、 如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,或者html,配置的视图解析器 InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。
2、如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。
3、如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。
Jackson的基本演绎法
com.fasterxml.jackson.annotation.*
@JsonIgnore:传送json时直接忽略该属性
@JsonFormat:将该属性数据格式化
@JsonInclude
SpringBoot开发环境热部署
使用devtools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
devtools可以实现页面热部署(即页面修改后会立即生效,这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实现)
实现类文件热部署(类文件修改后不会立即生效),并且会立即重启应用(发生在保存时机),注意:因为其采用的虚拟机机制,该项重启是很快的。
为什么重启很快:因为重启的时候只是加载了在开发的class,没有重新加载第三方的jar包。
# 关闭缓存,即时刷新
# spring.thymeleaf.cache=false
spring.thymeleaf.cache=true
# 热部署生效
spring.devtools.restart.enables=true
# 设置重启的目录,添加那个目录的文件需要restart
spring.devtools.restart.additional-paths=src/main/java
# 排除那个目录的文件不需要restart
# spring.devtools.restart.exclude=static/**,public/**
#classpath目录下的WEB-INF文件夹内容修改不重启
# spring.devtools.restart.exclude=WEB-INF/**
SpringBoot资源文件属性配置
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
@Configuration:配置
@ConfigurationProperties(prefix=""):配置属性的前缀
@PropertySource(value=“classpath:resource.properties”):指定配置文件
SpringBoot资源文件配置server以及tomcat
# 配置端口
server.port=8088
# 配置context-path
server.context-path=/IMooc
# 错误页,指定发生错误时,跳转的URL
server.error.path=/error
# session最大超时时间,默认为30分钟
server.session-timeout=60
# 该服务绑定IP地址,启动服务器时如本机不是该IP地址则抛出异常启动失败
server.address=192.168.1.2
# Server - tomcat 相关常用配置
############################################################
# Server - tomcat 相关常用配置
############################################################
# tomcat最大线程数, 默认为200
#server.tomcat.max-threads=250
# tomcat的URI编码
server.tomcat.uri-encoding=UTF-8
# 存放Tomcat的日志、Dump等文件的临时文件夹,默认为系统的tmp文件夹
#(如:C:\Users\Shanhy\AppData\Local\Temp)
#server.tomcat.basedir=H:/springboot-tomcat-tmp
# 打开Tomcat的Access日志,并可以设置日志格式的方法:
#server.tomcat.access-log-enabled=true
#server.tomcat.access-log-pattern=
# accesslog目录,默认在basedir/logs
#server.tomcat.accesslog.directory=
# 日志文件目录
#logging.path=H:/springboot-tomcat-tmp
# 日志文件名称,默认为spring.log
#logging.file=myapp.log
SpringBoot整合模板引擎
整合freemarker
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
配置文件:
############################################################
#
# freemarker 静态资源配置
#
############################################################
#设定ftl文件路径
spring.freemarker.template-loader-path=classpath:/templates
# 关闭缓存, 即时刷新, 上线生产环境需要改为true
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl
整合thymeleaf
添加依赖:
<!-- 引入 thymeleaf 模板依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
配置文件:
############################################################
#
# thymeleaf 静态资源配置
#
############################################################
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
# 关闭缓存, 即时刷新, 上线生产环境需要改为true
spring.thymeleaf.cache=false
常用标签的使用方法
条件判断 th:if
th:unless与th:if
循环 th:each
text与utext
th:switch与th:case
SpringBoot配置全局的异常捕获
- 页面跳转形式
- ajax形式
- 统一返回异常的形式
页面跳转形式
定义一个ExceptionHandler用于处理异常:
@ControllerAdvice
public class ErrorExceptionHandler {
private static final String LAI_ERROR_VIEW = "error";
@org.springframework.web.bind.annotation.ExceptionHandler(value = Exception.class)
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Exception e)throws Exception{
e.printStackTrace();
if(isAjax(request)){
return JSONResult.errorException(e.getMessage());
}else {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", request.getRequestURL());
mav.setViewName(LAI_ERROR_VIEW);
return mav;
}
}
public static boolean isAjax(HttpServletRequest httpRequest){
return (httpRequest.getHeader("X-Requested-With") != null
&& "XMLHttpRequest"
.equals( httpRequest.getHeader("X-Requested-With").toString()) );
}
}
再定义一个html用于显示异常界面,如上面的LAI_ERROR_VIEW。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 style="color: red">发生错误:</h1>
<div th:text="${url}"></div>
<div th:text="${exception.message}"></div>
</body>
</html>
ajax形式
与上种形式多增加一个ajax的js文件。
$.ajax({
url: "/err/getAjaxerror",
type: "POST",
async: false,
success: function(data) {
debugger;
if(data.status == 200 && data.msg == "OK") {
alert("success");
} else {
alert("发生异常:" + data.msg);
}
},
error: function (response, ajaxOptions, thrownError) {
debugger;
alert("error");
}
});
Springboot整合mybatis
- 使用generatorConfig生成mapper以及pojo
- 实现基于mybatis的CRUD功能
- 整合mybatis-pagehelper实现分页
- 自定义mapper的实现
在application.properties做一些配置:
############################################################
#
# mybatis 配置
#
############################################################
# mybatis 配置
mybatis.type-aliases-package=com.example.springbootdemo.pojo # 实体类生成的文件夹
mybatis.mapper-locations=classpath:mapper/*.xml # 将要存放mapper的文件夹 放在resources目录下
# 通用 Mapper 配置
mapper.mappers=com.example.springbootdemo.utils.MyMapper
mapper.not-empty=false
mapper.identity=MYSQL
# 分页插件配置
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
############################################################
#
# 配置数据源相关 使用阿里巴巴的 druid 数据源
#
############################################################
spring.datasource.url=jdbc:mysql://1.14.135.123:3306/springdemo
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.stat-view-servlet.allow=true
在根目录下创建generatorConfig.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="MysqlContext" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="com.imooc.utils.MyMapper"/>
</plugin>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://1.14.135.123:3306/springdemo"
userId="root"
password="123456">
</jdbcConnection>
<!-- 对于生成的pojo所在包 -->
<javaModelGenerator targetPackage="com.example.springbootdemo.pojo" targetProject="src/main/java"/>
<!-- 对于生成的mapper所在目录 -->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/>
<!-- 配置mapper对应的java映射 -->
<javaClientGenerator targetPackage="com.example.springbootdemo.mapper" targetProject="src/main/java"
type="XMLMAPPER"/>
<table tableName="sys_user"></table>
</context>
</generatorConfiguration>
根据配置生成对应的文件:
public class GeneratorDisplay {
public void generator() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
//指定 逆向工程配置文件
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
try {
GeneratorDisplay generatorSqlmap = new GeneratorDisplay();
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在SpringBootApplication添加注解:
@MapperScan(basePackages = "com.example.springbootdemo.mapper")
//扫描 所有需要的包, 包含一些自用的工具类包 所在的路径
@ComponentScan(basePackages= {"com.example.springbootdemo", "org.n3r.idworker"})
使用PageHelper分页
示例:
@Override
public List<SysUser> queryUserListPaged(SysUser user, Integer page, Integer pageSize) {
// 开始分页
PageHelper.startPage(page, pageSize);//page为第几页,pageSize为一页的大小
Example example = new Example(SysUser.class);
Example.Criteria criteria = example.createCriteria();
if (!StringUtils.isEmptyOrWhitespace(user.getNickname())) {
criteria.andLike("nickname", "%" + user.getNickname() + "%");
}
example.orderBy("registTime").desc();
List<SysUser> userList = userMapper.selectByExample(example);
return userList;
}
自定义mapper
在java的mapper文件夹中新建一个接口:
public interface SysUserMapperCustom {
List<SysUser> queryUserSimplyInfoById(String id);
}
在resources的mapper文件夹中新建一个mapper:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.SysUserMapperCustom" >
<!-- 查询简单的用户信息 -->
<select id="queryUserSimplyInfoById" resultType="com.imooc.pojo.SysUser"
parameterType="java.lang.String" >
select
*
from
sys_user
where
id = #{id,jdbcType=VARCHAR}
</select>
</mapper>
事务
在增删查改方法加一个注解:
@Transactional(propagation = Propagation.REQUIRED)//增删改
@Transactional(propagation = Propagation.SUPPORTS)//查
SpringBoot整合Redis
添加依赖:
<!-- 引入 redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在application.properties配置(不配则按照默认配置):
############################################################
#
# REDIS 配置
#
############################################################
# Redis数据库索引(默认为0)
spring.redis.database=1
# Redis服务器地址
spring.redis.host=192.168.1.191
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=1000
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=2
# 连接超时时间(毫秒)
spring.redis.timeout=0
使用:
//初始化一个template
@Autowired
private RedisTemplate<String, Object> redisTemplate;
//存入键值对
redisTemplate.opsForValue().set(key, value);
//获取键值对
redisTemplate.opsForValue().get(key);
一个redis的工具类:
public class RedisUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// @Autowired
// private StringRedisTemplate redisTemplate;
// Key(键),简单的key-value操作
/**
* 实现命令:TTL key,以秒为单位,返回给定 key的剩余生存时间(TTL, time to live)。
*
* @param key
* @return
*/
public long ttl(String key) {
return redisTemplate.getExpire(key);
}
/**
* 实现命令:expire 设置过期时间,单位秒
*
* @param key
* @return
*/
public void expire(String key, long timeout) {
redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 实现命令:INCR key,增加key一次
*
* @param key
* @return
*/
public long incr(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 实现命令:KEYS pattern,查找所有符合给定模式 pattern的 key
*/
public Set<String> keys(String pattern) {
return redisTemplate.keys(pattern);
}
/**
* 实现命令:DEL key,删除一个key
*
* @param key
*/
public void del(String key) {
redisTemplate.delete(key);
}
// String(字符串)
/**
* 实现命令:SET key value,设置一个key-value(将字符串值 value关联到 key)
*
* @param key
* @param value
*/
public void set(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 实现命令:SET key value EX seconds,设置key-value和超时时间(秒)
*
* @param key
* @param value
* @param timeout
* (以秒为单位)
*/
public void set(String key, String value, long timeout) {
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
/**
* 实现命令:GET key,返回 key所关联的字符串值。
*
* @param key
* @return value
*/
public String get(String key) {
return (String)redisTemplate.opsForValue().get(key);
}
// Hash(哈希表)
/**
* 实现命令:HSET key field value,将哈希表 key中的域 field的值设为 value
*
* @param key
* @param field
* @param value
*/
public void hset(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}
/**
* 实现命令:HGET key field,返回哈希表 key中给定域 field的值
*
* @param key
* @param field
* @return
*/
public String hget(String key, String field) {
return (String) redisTemplate.opsForHash().get(key, field);
}
/**
* 实现命令:HDEL key field [field ...],删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
*
* @param key
* @param fields
*/
public void hdel(String key, Object... fields) {
redisTemplate.opsForHash().delete(key, fields);
}
/**
* 实现命令:HGETALL key,返回哈希表 key中,所有的域和值。
*
* @param key
* @return
*/
public Map<Object, Object> hgetall(String key) {
return redisTemplate.opsForHash().entries(key);
}
// List(列表)
/**
* 实现命令:LPUSH key value,将一个值 value插入到列表 key的表头
*
* @param key
* @param value
* @return 执行 LPUSH命令后,列表的长度。
*/
public long lpush(String key, String value) {
return redisTemplate.opsForList().leftPush(key, value);
}
/**
* 实现命令:LPOP key,移除并返回列表 key的头元素。
*
* @param key
* @return 列表key的头元素。
*/
public String lpop(String key) {
return (String)redisTemplate.opsForList().leftPop(key);
}
/**
* 实现命令:RPUSH key value,将一个值 value插入到列表 key的表尾(最右边)。
*
* @param key
* @param value
* @return 执行 LPUSH命令后,列表的长度。
*/
public long rpush(String key, String value) {
return redisTemplate.opsForList().rightPush(key, value);
}
}
一个json转换类:
public class JsonUtils {
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 将对象转换成json字符串。
* <p>Title: pojoToJson</p>
* <p>Description: </p>
* @param data
* @return
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将json结果集转化为对象
*
* @param jsonData json数据
* @param clazz 对象中的object类型
* @return
*/
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成pojo对象list
* <p>Title: jsonToList</p>
* <p>Description: </p>
* @param jsonData
* @param beanType
* @return
*/
public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
SpringBoot整合定时任务task
使用注解@EnableScheduling开启定时任务,会自动扫描
定义@Component作为组件被容器扫描
使用@Scheduled(cron = “”)做定时任务。
表达式生成地址:http://cron.qqe2.com
SpringBoot异步执行程序
使用注解@EnableAsync开启异步,会自动扫描。
定义@Component@Async作为组件被容器扫描执行
SpringBoot拦截器的使用
使用注解@Configuration配置拦截器
继承WebMvcCOnfigurerAdapter(已过时),取代的方法有两种:
①implements WebMvcConfigurer(官方推荐)
②extends WebMvcConfigurationSupport
重写addInterceptors添加需要的拦截器地址
@Configuration
public class TestConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
/**
* 拦截器按照顺序执行
*/
// registry.addInterceptor(new TwoInterceptor()).addPathPatterns("/th/**")
// .addPathPatterns("/user/**");
registry.addInterceptor(new OneInterceptor()).addPathPatterns("/user/**");
}
}
拦截器:
public class OneInterceptor implements HandlerInterceptor {
/**
* 在请求处理之前进行调用(Controller方法调用之前)
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object object) throws Exception {
System.out.println("被one拦截,放行...");
return true;
/*if (true) {
returnErrorResponse(response, IMoocJSONResult.errorMsg("被one拦截..."));
}
return false;*/
}
/**
* 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object object, ModelAndView mv)
throws Exception {
// TODO Auto-generated method stub
}
/**
* 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行
* (主要是用于进行资源清理工作)
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object object, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
public void returnErrorResponse(HttpServletResponse response, JSONResult result)
throws IOException, UnsupportedEncodingException {
OutputStream out=null;
try{
response.setCharacterEncoding("utf-8");
response.setContentType("text/json");
out = response.getOutputStream();
out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
out.flush();
} finally{
if(out!=null){
out.close();
}
}
}
}