整合SpringMvc
虽然默认配置已经可以使用SpringMVC了,不过有时候需要自定义配置。
修改端口
server:
port: 8081
访问静态资源
现在我们的项目是一个jar工程,那么就没有webapp,那么静态资源该放在哪?
在前面查看自动配置原理的时候看到有一个ResourceProperties的类,里面定义了静态资源的默认查找路径。
https://blog.youkuaiyun.com/mashaokang1314/article/details/90581204
默认的静态资源路径为:
- “classpath:/META-INF/resources/”
- “classpath:/resources/”,
- “classpath:/static/”
- “classpath:/public/”
只要把静态资源放在这些目录中的任何一个,SpringMVC都会帮我们处理。
创建一个static目录,并且存放图片并访问:
启动服务器并访问路径:
添加拦截器
拦截器不是一个普通属性,而是一个类,所以就要用到java配置方式,SpringBoot官方文档中的一段说明:
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own
@Configuration
class of typeWebMvcConfigurer
but without@EnableWebMvc
. If you wish to provide custom instances ofRequestMappingHandlerMapping
,RequestMappingHandlerAdapter
, orExceptionHandlerExceptionResolver
, you can declare aWebMvcRegistrationsAdapter
instance to provide such components.
If you want to take complete control of Spring MVC, you can add your own@Configuration
annotated with@EnableWebMvc
.
翻译:
如果你想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器, 视图控制器、消息转换器 等等),你应该让一个类实现
WebMvcConfigurer
,并且添加@Configuration注解,但是千万不要加@EnableWebMvc
注解。如果你想要自定义HandlerMapping
、HandlerAdapter
、ExceptionResolver
等组件,你可以创建一个WebMvcRegistrationsAdapter
实例 来提供以上组件。
如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加@Configuration
注解和@EnableWebMvc
注解
总结:通过实现WebMvcConfigurer
并添加@Configuration
注解来实现自定义部分SpringMvc配置。
- 首先定义一个拦截器
public class LoginInterceptor implements HandlerInterceptor {
//定义日志对象
private static final Logger log=LoggerFactory.getLogger(LoginInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("preHandle method is invoked...");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
log.info("postHandle method is invoked...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
log.info("afterCompletion method is invoked...");
}
}
- 定义配置类,注册拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/**
* 通过@Bean注解,将自定义的拦截器注册到spring容器
* @return
* **/
@Bean
public LoginInterceptor loginInterceptor(){
return new LoginInterceptor();
}
/**
* 重写接口中的addInterceptors方法,添加自定义拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//通过registry来注册拦截器,通过addPathPatterns来添加拦截路径
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
}
}
接下来运行并查看日志,但是你会发现日志中什么都没有,因为我们记录的lig级别是debug,默认显示info以上,所以需要配置日志。
运行查看日志:
还可以通过注解方式来打开日志
注入依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
整合jdbc和事务
我们只要找到SpringBoot提供的启动器即可:
<!--Jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--Mysql数据库启动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
整合连接池
其实在刚才引入jdbc启动器的时候,SpringBoot已经自动帮我们引入了一个连接池:
HikariCP是目前速度最快的连接池了,来看看对比:
因为SpringBoot在引入jdbc启动器的时候,自动引入hikari连接池的配置;
#jdbc
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
username: root
password: westos
hikari:
minimum-idle: 10
maximum-pool-size: 30
idle-timeout: 60000
与MyBatis整合
- 添加依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
- 配置
mybatis:
type-aliases-package: com.example.pojo
mapper-locations: classpath:mappers/*.xml
注意,这里没有配置mapper接口扫描包,因此我们需要给每一个Mapper接口添加@Mapper注解,才能被识别。
@Mapper
public class UserMapper {
}
通用Mapper
极其方便的使用MyBatis单表的增删改查。支持单表操作,不支持通用的多表联合查询。
通用Mapper的作者也为自己的插件写了启动器,可以直接引用:
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
这个启动器也引入了mybatis、Spring、jdbc、mybatis-Spring的启动器。所以之前引入的重复依赖可以删除。并且自带了mybatis中的驼峰命名配置,所以之前mybatis属性中的# map-underscore-to-camel-case: true
可以不用指定。
生成一个User类
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;
import javax.persistence.Id;
import javax.persistence.Table;
@Data
//如果类的名字和数据表名字不一样,则通过@Table来指定
@Table(name = "abc")
public class User {
//指定主键
@Id
//指定自增主键
@KeySql(useGeneratedKeys = true)
private Integer a;
private String b;
private String c;
private String d;
private String e;
//瞬时主键,不会持久化到数据库
// @Transient
}
来创建一个UserMapper接口,并且继承通用Mapper里的Mapper接口
import com.example.pojo.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User> {
}
写一个测试类:选中UserMapper然后按ctrl+shift+t
整合单元测试
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
UserMapper userMapper;
//根据主键查询的方法
@Test
public void queryId(){
User user = userMapper.selectByPrimaryKey(1);
System.out.println(user);
}
}
可以看到userMapper继承通用Mapper之后,里面的sql操作方法都有了,不用自己写了:
在启动类上配置mapper接口扫描器
注意
在创建user对象的时候,通用Mapper对于主键的int类型无法识别,所以要指定成Interger类型。
指定为int类型的查询结果:
正确的查询结果:
- banner可以自定义
- 先进入网站生成艺术字点击进入
- 拷贝粘贴,放入resources banner.txt
- lombok
可以加在模型类上,帮助生成get、set、toString、hashCode等方法;
(1) 在项目中添加lombok依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
(2) 在编辑器上安装lombok
- idea插件 settings Plugins 搜索安装
- eclipse 插件
(3) 注解
- @Data :生成get、set、toString、hashCode等方法;
- @AllArgsConstructor 根据所有属性,生成一个带参的构造方法;
- @NoArgsConstructor 生成无参构造方法;
- @Builder 建造器模式
- @Getter 只生成get方法
- @Setter 只生成set方法
使用Ctrl+F12 查看生成的方法
- @Slf4j :为当前的类生成一个日志对象
@Service
@Slf4j // 相当于生成了private static final Logger log = LoggerFactory.getLogger(StudentService.class);
public class StudentServiceImpl implements StudentService{
@Autowired
private StudentDao studentDao;
@Override
public List<Student> findAll() {
return studentDao.findall();
}
@Override
public void add(int a, int b) {
//判断是否为debug的日志级别
if(log.isDebugEnabled()){
log.debug("a:"+a);
}
log.debug("b:{}",b);
}
}
在application.properties文件中设置debug,表示打印StudentServiceImpl包下的debug日志信息;
logging.level.com.westos.day47springboot.service.StudentServiceImpl=debug
spring Boot 开发工具
devtools
让修改代码快速生效,提高服务器启动速度
添加依赖
<!-- spring boot 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 开发工具, 让修改代码快速生效, 提高服务器启动速度 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
在idea 修改代码之后,执行build ->build module 会触发服务的重新启动,这里的重新启动只加载修改的类,而不是将全部类再加载;
- ctrl+shilf+a
- 搜索registry…
- 搜索 compiler.automake.allow.when.app.running 打钩
监控工具
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
默认已经开启两个端点 /info /health
如果开发中希望使用更多的端点 在application.properties文件中添加
management.endpoints.web.exposure.include=*
- 其中/beans 是用来检查spring容器中所有对象;
- /env 是显示当前所有系统环境变量、java变量的一个端点、springboot自己的配置信息
主义生产环境下不要暴露这些端点;
新的管理 bean的方式
创建配置类使用@Configuration
注解,表示这个类是专门用来进行容器配置的类
@Configuration // 配置, 表示这个类是专门用来进行 容器配置的类
@Slf4j
public class MyConfig {
// <bean id="userService" class="UserService">
// 工厂方法, 生产一个希望由 spring 管理的对象
@Bean
public UserService userService() {
log.info("调用了 userService ....");
return new UserService();
}
自动创建数据库
resources
- schema.sql 存放删表建表语句 sql
drop table if exists user2;
create table user2(
id int primary key auto_increment,
username varchar(20) not null
);
- data.sql 存放insert数据的sql
insert into user2(username) values ('zhangsan');
insert into user2(username) values ('lisi');
insert into user2(username) values ('wangwu');
spring.datasource.initialization-mode=always
spring boot 继承jdbc
JdbcTemplate jdbc 模板类
- 添加依赖
<!--springboot 结合jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
@Repository专门加在数据访问层上
- 为dao类注入jdbcTemplate属性
@Repository
public class StudentDao {
@Autowired
private JdbcTemplate jdbc;
public void insert(String name,Date birthday,String sex){
String sql="insert into student(sid,sname,birthday,sex) values(null,?,?,?)";
jdbc.update(sql,name,birthday,sex);
}
public List<Student> findAll(){
String sql="select * from student";
return jdbc.query(sql,new BeanPropertyRowMapper<>(Student.class));
}
public Student findById(int sid){
String sql="select * from student where sid=?";
return jdbc.queryForObject(sql,new BeanPropertyRowMapper<>(Student.class),sid);
}
}
事务控制
在入口类MyApplication上加上@EnableTransactionManagement
注解启动事务管理,需要事务的方法上加上@Transactional
注解
面向切面编程
@EnableAspectJAutoProxy
启用面向切面编程的注解;
Thymeleaf快速入门
SpringBoot并不推荐使用jsp,但是支持一些模板引擎技术:比如Thymeleaf。
为什么使用Thymeleaf?
简单地说,Thymeleaf是一个跟Velocity、FreeMarker类似的模板引擎,它可以完全替代JSP。相较于其他模板,它有一下吸引人的特点:
- 动静结合:Thymeleaf在有网络和无网络的环境下皆可运行,它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看数据的动态页面效果。这是由于它支持HTML原型,然后在html标签里增加额外的属性来达到模板+数据的方式。浏览器解释html时会忽略未定义的标签属性,所以Thymeleaf的模板可以静态运行;当数据返回到页面时,Thymeleaf标签会动态地替换掉静态内容,使页面动态显示。
- 开箱即用:它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
- 多方言支持:Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
- 与SpringBoot完美整合,SpringBoot提供了Thymeleaf的默认配置,并且为Thymeleaf设置了视图解析器,我们可以像以前操作jsp一样来操作Thymeleaf。代码几乎没有任何区别,就是在模板语法上有区别。
编写接口
注意不能返回json形式,所以将@RestController
换为@Controller
@GetMapping("/all")
public String all(ModelMap model){
List<User> users = this.userService.queryAll();
model.addAttribute("users",users);
return "users";
}
引入启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
SpringBoot会自动为Thymeleaf注册一个视图解析器:
与解析JSP的InternalViewReslover类似,Thymeleaf也会根据前后缀来确定模板文件的位置:
- 前缀为:
classpath:/templates/
- 后缀为:
.html
如果我们返回的时users
视图,会指向到classpath:/templates/users.html
静态页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
<style type="text/css">
table {border-collapse: collapse; font-size: 14px; width: 80%; margin: auto}
table, th, td {border: 1px solid darkslategray;padding: 10px}
</style>
</head>
<body>
<div style="text-align: center">
<span style="color: darkslategray; font-size: 30px">欢迎光临!</span>
<hr/>
<table class="list">
<tr>
<th>a</th>
<th>b</th>
<th>c</th>
<th>d</th>
<th>e</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.a}"</td>
<td th:text="${user.b}"</td>
<td th:text="${user.c}"</td>
<td th:text="${user.d}"</td>
<td th:text="${user.e}"</td>
</tr>
</table>
</div>
</body>
</html>
模板缓存
Thymeleaf会在第一次对模板解析之后进行缓存,极大地提高了并发处理能力。但是这也给我们开发带来了不便,修改页面后并不会立即看到效果,开发阶段可以关闭缓存使用:
spring.thymeleaf.cache=false
注意在idea中,需要在修改页面后按快捷键ctrl+shft+F9
对项目rebuild才可以。