一、用Maven建时的相关导包
在 pom.xml 中添加 Spring Boot 相关的父级依赖, spring-boot-starter-parent 是一个特殊的starter,它提供
了项目相关的默认依赖,使用它之后 ,常用的包依赖可以省去 version 标签。
<parent>
<artifactId>spring-boot-starter-web</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.4.4</version>
</parent>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lx</groupId>
<artifactId>spring-Boot-01-hello</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- spring-boot-starter-parent是当前项目的父依赖
spring-boot-starter-parent 继承 spring-boot-dependencies
spring-boot-dependencies里面定义了很多组件版本号,我们引用对应依赖时,不需要写<version>标签-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
</parent>
<!-- spring-boot-starter-web
spring-boot-starter :它是springboot的场景启动器,针对不同场景定义了很多场景的启动器
项目需要使用那些场景启动器,就直接依赖对应的启动器就可以了-->
<!-- spring-boot-starter-web 构建Web项目,比如:tomcat,springmvc-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- 可以将当前项目打成一个jar包进行运行 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
关于注解@SpringBootApplication
用于标识,一个引导力,说明当前是一个Springboot项目,其构成的关键注解:
- 1.@SpringBootConfiguration
@Configuration 它属于spring中的一个注解,定义配置类,等价于配置文件
@Component 添加到spring容器中,表示是一个组件 - 2.@EnableAutoConfiguration
@AutoConfigurationPackage 将引导类所在的包及子包下面所有的组件添加到 spring 容器中
@Import({AutoConfigurationImportSelector.class})
1.将所有组件以全类名的方式返回,并且添加到spring 容器中
2.会给容器中导入非常多的自动配置类(…AutoConfiguration),省去手动编写配置然后注入到组件中 - 3.@ComponentScan
被该注解标识的类,会被spring容器进行管理
二、使用Spring Initializr 构建项目
resources 文件夹中目录结构:
- static :保存所有的静态资文件, js css images
- templates :保存所有的模板页面(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页
面),可以使用模板引擎(freemarker、thymeleaf); - application.properties :Spring Boot应用的配置文件;可以修改一些默认设置;
如修改默认端口 server.prot=8081
三、springboot核心配置
Spring Boot 使用一个全局配置文件,放置在 src/main/resources 目录或类路径的 /config 下;
- application.properties
- application.yml
配置文件的作用:修改 Spring Boot 自动配置的默认值;
#修改Servlet相关配置 server.servlet.xxx
#端口名加/servlet加/hello才可请求
server.servlet.context-path=/servlet
yml 是 YAML(YAML Ain’t Markup Language)不是一个标记语言;
标记语言:以前的配置文件;大多都使用的是 xxxxx.xml文件;
<server>
<port>8081</port>
</server>
YAML:以数据为中心,配置数据的时候具有面向对象的特征;比 json、xml 等更适合做配置文件;
server:
port: 8081
- key: value 表示一对键值对(冒号后面必须要有空格)
- 使用空格缩进表示层级关系
- 左侧缩进的空格数目不重要,只要同一层级的元素左侧对齐即可
- key 与 value 大小写敏感
- @ConfigurationProperties 告诉SpringBoot将配置文件中对应属性的值,映射到这个组件类中,进行一一绑定
- prefix = “emp”:配置文件中的前缀名,哪个前缀与下面的所有属性进行一一映射
- @Component 必须将当前组件作为SpringBoot中的一个组件,才能使用容器提供的 @ConfigurationProperties功能,@Component 组件,等价于<bean id=“xx” class=“com.lx.xx”》
测试类中的注解
@RunWith(SpringRunner.class) : 在当前这个测试类,可以把所有组件都拿到
@Autowired : 其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property,实现自动装配
四、获取值
1、 @Value :
- @Value("${xxx.name}"):将.yml或.properties中的xxx中的某个值赋给该注释下的变量,用美元符
- @Value("#{10*2}"):计算后赋值,直接用#
- @Value(“8000”):直接赋值
2、 @ConfigurationProperties(prefix = “xxx”)
- 将 .yml或.properties直接一一对应赋值
五、操作使用.xml配置文件
SpringBoot提倡零配置, 即无xml配置,但是在实际开发中,可能有一些特殊要求必须使用 xml 配置;
这时我们可以通过 Spring 提供的 @ImportResource 来加载 xml 配置文件。
1、在service层建立一个方法
public class EmpService {
public void add(){
System.out.println("测试一下");
}
}
2、建立一个.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="empService" class="com.lx.springboot.service.EmpService">
</bean>
</beans>
3、main方法上加注解@ImportResource(locations = {“xxx.xml”})
@ImportResource(locations = {"classpath:spring-01.xml"})
@SpringBootApplication
public class SpringBoot02ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot02ConfigApplication.class, args);
}
}
4、测试方法
@Autowired
ApplicationContext context;
@Test
public void testxml(){
EmpService empService = context.getBean("empService",EmpService.class);
System.out.println(empService);
empService.add();
}
六、自定义配置类向容器注入组件
第五点不提倡,但有些时候却不得不用,Spring Boot 推荐使用注解的方式向容器中注入组件
操作如下:
-
使用 @Configuration 配置类,来表示对应Spring配置文件
-
使用 @Bean 向容器中注入组件对象
-
@Configuration 等价于beans.xml
-
@Bean 类似bean标签
//注册一个bean ,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的class属性
@Configuration
public class EmpConfig {
@Bean
public EmpService empService2(){
System.out.println("再次测试一下,EmpService 组件注入成功");
return new EmpService();
}
}
测试:
@Test
public void testxml(){
EmpService empService2 = context.getBean("empService2",EmpService.class);
System.out.println(empService2);
}
七、Profile 多环境支持
Profile 是 Spring 用来针对不同的环境要求,提供不同的配置支持, 全局 Profile 配置使用的文件名可以是
application-{profile}.properties / application-{profile}.yml ;
如: application-dev.properties / application-prod.properties
在yml中:
server:
port: 8081 # 默认配置的端口号
spring:
profiles: dev # 激活哪个profile , 当前激活的是 dev 开发环境
---
server:
port: 8082
spring:
profiles: dev # 指定属于哪个环境, dev 环境时使用
---
server:
port: 8088
spring:
profiles: prod # 指定属于哪个环境, prod 环境时使用
八、日志
若出现java: 不兼容的类型: java.lang.String无法转换为java.util.function.Supplier<java.lang.String>
那就是idea导包导错了
正确的应该是:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Logger logger = LoggerFactory.getLogger(getClass());
九、模板引擎Thymeleaf
<!-- thymeleaf 模板启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
通过模板加上响应的数据即可得到想要的输出,类似固定句式加上一个名称。
.html中导入,后面th: 将会有提示
<html lang="en" xmlns:th="http://www.thymeleaf.org">
@RequestMapping("/success")
public String success(Map<String,Object> map){
map.put("name","张三");
//将会去找classpath:/templates/success.html
return "success";
}
不需要@ResponseBody,因为我们是加载页面,而不是将success这个字符串打印到页面中
<p th:text="${name}">这里的名字将会被覆盖</p>
通过th:text="${xx}"进行赋值
th:value="${xxx}"用于回显
th里面的拼接@{/provider/} + ${p.pid} + ‘?type=update’
几个标号相连或加上‘ ’(单引号)
基本语法:
User.java中有private String username;和 private Integer gender;
<table border="1px">
<tr>
<th>姓名</th>
<th>性别</th>
</tr>
<tr th:each="user :${userList}">
<td th:text="${user.username}">hehe</td>
<td th:text="${user.gender == 1 ?'女':'男'}">haha</td>
</tr>
</table>
@RequestMapping("/study")
public String study(Map<String,Object> map){
List<User> userList = new ArrayList<>();
userList.add(new User("张三",2));
userList.add(new User("李四",1));
userList.add(new User("王五",2));
map.put("userList",userList);
return "study";
}
十、SpringBoot 热部署
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
开发环境下:
#开发环境下关闭thymeleaf模板缓存,thymeleaf默认是开启状态
spring.thymeleaf.cache=false
这样idea中 Ctrl+F9 就可以去网页看了
十一、controller和config注解
在controller中,在方法上面加上@Controller,标识为控制层
- @RequestMapping(value = “/providers”,method = RequestMethod.GET)
通过get方法去找providers - @GetMapping("/providers")
上面那个的化简版
在config中,加上@Configuration。创建自己的webMVC,再用@Bean实现注入,可做到和controller中加载页面的方法。
十二、拦截器
@Configuration
public class MySpringMvcConfigurer {
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("main/login");
registry.addViewController("/index.html").setViewName("main/login");
registry.addViewController("/main.html").setViewName("main/index");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
//拦截所有请求 /**
.addPathPatterns("/**")
// 排除不需要拦截的请求
.excludePathPatterns("/", "/index.html", "/login")
//SpringBoot2+中要排除静态资源路径, 因访问时不会加/static,所以配置如下
.excludePathPatterns("/css/**", "/img/**","/js/**");
}
};
}
public class LoginHandlerInterceptor implements HandlerInterceptor {
//调用目标方法之前被拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object loginUser = request.getSession().getAttribute("loginUser");
if(loginUser != null){
//已经登录过,放行
return true;
}
//没有登录过
request.setAttribute("msg","没有权限,请先登录!");
//转到登录页面
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}
}
十三、Thymeleaf与controller
@GetMapping("/logout")
public String logout(HttpSession session){
session.removeAttribute("loginUser");
session.invalidate();
return "redirect:/index.html";
}
<a th:href="@{/logout}" href="../main/login.html">
十四、 Restful 架构
十五、三大组件Servlet/Filter/Listener
Spring提供以下Bean来注册三大组件:
- ServletRegistrationBean :注册自定义Servlet
- FilterRegistrationBean :注册自定义Filter
- ServletListenerRegistrationBean :注册自定义Listener
@Configuration
public class MyServletConfig {
@Bean
public ServletRegistrationBean helloSevlet() {
ServletRegistrationBean<HelloServlet> bean = new ServletRegistrationBean<>(new HelloServlet(), "/hello");
bean.setLoadOnStartup(1);
return bean;
}
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
//指定过滤器
bean.setFilter(new MyFilter());
//过滤哪些请求
bean.setUrlPatterns(Arrays.asList("/hello"));
return bean;
}
@Bean
public ServletListenerRegistrationBean myListener() {
return new ServletListenerRegistrationBean(new MyListener());
}
}
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("MyFilter 过滤完成");
//放行
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("filter销毁");
}
}
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("SpringBoot.Servlet应用启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("SpringBoot.Servlet应用销毁");
}
}
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello servlet success");
}
}
十六、整合jdbc
controller层用@RestController等价于
@Controller + @ResponseBody
yml文件配置连接
spring:
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/jdbcstudy?serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
java中写sql
@Autowired
JdbcTemplate jdbcTemplate;
@GetMapping("providers")
public Map list(){
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from provider");
Map<String, Object> map = maps.get(0);
return map;
}
十七、druid连接池
首先导入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
yml中进行相关配置
spring:
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/jdbcstudy?serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置, DataSourceProperties中没有相关属性,默认无法绑定
initialSize: 8
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,logback
maxPoolPreparedStatementPerConnectionSize: 25
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
自定义配置类, 将配置中属性与 DruidDataSource 属性绑定
import javax.sql.DataSource;
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
}
启动后结果和上一大点的jdbc的运行结果相同
配置Druid监控
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
/**
* 配置Druid监控
* 1. 配置一个管理后台的Servlet
* 2. 配置一个监控的filter
*/
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
Map<String,String> initParam = new HashMap<>();
//访问的用户名密码
initParam.put(StatViewServlet.PARAM_NAME_USERNAME, "root");
initParam.put(StatViewServlet.PARAM_NAME_PASSWORD, "123");
//允许访问的ip,不写默认所有ip访问
initParam.put(StatViewServlet.PARAM_NAME_ALLOW, "");
//禁止访问的ip
initParam.put(StatViewServlet.PARAM_NAME_DENY, "192.168.10.1");
bean.setInitParameters(initParam);
return bean;
}
//2. 配置一个监控的filter
@Bean
public FilterRegistrationBean filter() {
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
bean.setFilter(new WebStatFilter());
//配置初始化参数
Map<String, String> initParam = new HashMap<>();
//排除请求
initParam.put(WebStatFilter.PARAM_NAME_EXCLUSIONS, "*.js,*.css,/druid/*");
//拦截所有请求
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
就可以打开这个神奇的页面
十八、整合mybatis
@PathVariable 映射 URL 绑定的占位符
注解版:
mapper层中(一个接口,包含相关的数据操作请求):
@Mapper
public interface ProviderMapper {
@Select("select * from provider where pid = #{pid}")
Provider getProvierByPid(Integer pid);
//useGeneratedKeys是否使用自增主键,keyProperty指定实体类中的哪一个属性封装主键值
@Options(useGeneratedKeys = true, keyProperty = "pid")
@Insert("insert into provider(providerName) values(#{providerName})")
int addProvider(Provider provider);
@Delete("delete from provider where pid=#{pid}")
int deleteProviderByPid(Integer pid);
@Update("update provider set providerName=#{providerName} where pid=#{pid}" )
int updateProvider(Provider provider);
}
controller层中(对于SQL操作的java代码):
@RestController
public class ProviderController {
@Autowired
ProviderMapper providerMapper;
@GetMapping("/provider/{pid}")
public Provider getProvider(@PathVariable("pid")Integer pid){
Provider provider = providerMapper.getProvierByPid(pid);
return provider;
}
@GetMapping("/provider")
public Provider addProvider(Provider provider){
providerMapper.addProvider(provider);
return provider;
}
}
此时页面请求http://localhost:8080/provider/1即可查询到相应的JSON数据。
开启驼峰式(自定义MyBatis配置类, 替代mybatis配置文件):
@Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return new ConfigurationCustomizer(){
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
配置文件版:
BillMapper.java
public interface BillMapper {
Bill getBillByBid(Integer bid);
int insertBill(Bill bill);
}
BillMapper.xml
<?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.lx.springboot.mapper.BillMapper">
<select id="getBillByBid" resultType="com.lx.springboot.entities.Bill">
select * from bill where bid=#{bid};
</select>
<insert id="insertBill">
insert into bill(bill_code, bill_name) values(#{billCode}, #{billName});
</insert>
</mapper>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--mybatis核心配置文件-->
<settings>
<!--开启驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
yml中
mybatis:
#核心配置文件路径
config-location: classpath:mybatis/mybatis-config.xml
#映射配置文件路径
mapper-locations: classpath:mybatis/mapper/*.xml
controller
@RestController
public class BillController {
@Autowired
BillMapper billMapper;
@GetMapping("/bill/{bid}")
public Bill getbill(@PathVariable("bid")Integer bid){
Bill bill = billMapper.getBillByBid(bid);
return bill;
}
@GetMapping("/bill")
public Bill addProvider(Bill bill){
billMapper.insertBill(bill);
return bill;
}
}
十九、jpa
yml中连接好数据库
spring:
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/jpa?serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
# 会根据就映射实体类自动创建或更新数据表
ddl-auto: update
# 控制台显示SQL
show-sql: true
创建实体类, 并使用JPA注解进行配置映射关系
- 类上使用 JPA注解 @Entity 标注,说明它是和数据表映射的类; @Table(name=“表名”) 指定对应映射的表名,
省略默认表名就是类名。 - @Id 标识主键, @GeneratedValue(strategy = GenerationType.IDENTITY) 标识自增长主键
- @Column 标识字段
entity.User.java
package com.lx.springboot.entity;
import javax.persistence.*;
/**
* jpa采用的是Orm(对象关系映射)模型
*/
@Entity
@Table(name = "tbl_user")
public class User {
@Id //标识主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //标识自增长主键
private Integer id;
@Column(name = "user_name",length = 5) //这是和数据表对应的一个列
private String userName;
@Column //省略默认列名就是属性名
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
dao.UserRepository.java
package com.lx.springboot.dao;
import com.lx.springboot.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
//自定义接口继承JpaRepository,就会crud及分页等基本功能
//指定的泛型<操作的实体类,主键的类型>
public interface UserRepository extends JpaRepository<User,Integer> {
}
controller层中
@RestController
public class UserController {
@Autowired
UserRepository userRepository;
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Integer id) {
return userRepository.findById(id).get();
}
@GetMapping("/user")
public User addUser(User user) {
return userRepository.save(user);
}
}
测试即可使用
二十、事务管理
启动类上添加
@EnableTransactionManagement
//开启注解的事务管理
service层的方法上加上@Transactional
开启事务管理
在yml中
# 指定引擎: 创建的表类型是Innodb,才可以进行对事物的回滚。
database-platform: org.hibernate.dialect.MySQL57Dialect
@Transactional(isolation = Isolation.DEFAULT)
指定隔离级别
@Transactional(isolation = Isolation.DEFAULT)
指定传播行为
相关报错:
- Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method ‘POST’ not supported]
在配置文件中加上:
spring.mvc.hiddenmethod.filter.enabled=true
mybatis的配置文件中的SQL不要复制粘贴,容易出事
如果真出现了变绿色的恶心的情况,给表加个别名就可以了