项目使用的是spring-boot,所以在这里先学习该框架。在使用SSM框架的时候,最头疼的就是环境搭建了,各种配置不照文档很难配下来,即使现在记住了,过段时间再来肯定还是忘了而且导包也很麻烦,因为巨多(传统开发的问题之一就是依赖管理混乱)。使用spring-boot的好处就是省去了这些麻烦的配置,让我们快速搭建起来开发环境。很多人肯定和我一样很早就有用过spring-boot,但还是希望一起过一遍,接下来会不讲原理但会在使用上讲的很详细。相信学完这部分会有不小的帮助,比如讲到了好用的lombok和通用Mapper。 | |
---|---|
该学习资料来源于某马的大数据项目,虽然是练手的项目,但是之前在面试中帮助了我很多,再次感谢。如果需要参加校招,希望这篇对你有帮助。菜鸡的秋招之路。另外附上本人的leetcode300题(Java版),觉得可以的帮忙star哈,有问题尽管问大家一起探讨,以前忙加上自己太菜所以很少回答问题。
1. spring-boot的简单使用
1)首先创建maven项目,注意是个普通的工程
2)导包
SpringBoot提供了一个名为spring-boot-starter-parent的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样我们就不用操心依赖的版本问题了,需要什么依赖,直接引入坐标即可!如下
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
为了让SpringBoot帮我们完成各种自动配置,我们必须引入SpringBoot提供的自动配置依赖,我们称为启动器。因为我们是web项目,这里我们引入web启动器:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
如果你的maven使用的jdk不是jdk8,那么进行指定
<properties>
<java.version>1.8</java.version>
</properties>
完整的依赖如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
3)编写启动类和Controller
创建启动类WebApplicationStarter ,使用@SpringBootApplication注解指定该类为spring-boot的应用程序类,一个工程只此一个。main方法里面如下
@SpringBootApplication
public class WebApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(WebApplicationStarter.class, args);
}
}
创建Controller如下,很简单就不解释了
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello spring-boot!";
}
}
到这里可以理解为SpringMVC的环境搭建好了(等同于web.xml里面已经配置好了,springmvc的配置文件里面的啥视图解析器,适配器,映射器都配好了),Controller也写好了,运行main方法也没就可以访问了。
上面的介绍比较繁琐,其实就3步
- 创建maven工程
- 配父左边,导入启动器
- 写启动类
注意:启动类我是放在com.scu包下的,那么以后写的所有的类均需要放在该包或者子包下面,否则扫描不到(实际上使用了@ComponentScan注解,相当于主键扫描,而扫描的路径就是启动类所在路径,具体的也没去深究了)。
2. 使用Java配置
肯定很多同学和我一样,在学习spring和springmvc的时候,使用了applcation.xml在里面配置了大量的bean,比如配置了连接池DataSource,但是官方很早就推荐我们使用Java配置来代替xml配置了。直到接触到了spring-boot项目才知道原来可以使用Java配置,我们作为Java程序员,使用Java配置肯定是比写xml来的更直观。方式有很多种,一种种来看,选择自己喜欢的吧。
使用Java配置的方式来完成连接池的配置
引入配置文件db.properties,放在目录resource下
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/e3mall_32?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
引入数据源依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
1)第一种方式
@Configuration //指定为配置类
@PropertySource("classpath:db.properties") //读取配置文件
public class JdbcConfig {
@Value("${jdbc.driverClass}")
private String driverClass;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean //返回bean放在spring容器中
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
重启下项目,这时候在容器中就有这个DataSource了。
@Configuration:声明一个类作为配置类,代替xml文件
@Bean:声明在方法上,将方法的返回值加入Bean容器,代替标签
@value:属性注入
@PropertySource:指定外部属性文件
然后我们就可以在任意位置通过@Autowired注入DataSource了!
2)第二种方式
是不是觉得引入配置文件db.properties,然后读取,使用@Value注入的方式还差那么点意思?第二种方式,使用Java类来替换掉db.properties文件。
1、创建application.properties文件,放在resource目录下,将db.properties文件的内容复制进去(随着项目的重启,会重新读取application.properties文件)。
2、编写JdbcProperties类
在这之前介绍一个好用的库,lombok,比如使用它提供的注解@Data,就会生成对应属性的get/set,toString等方法。导入依赖如下
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
另外,不管是eclipse还是idea都需要安装对应的插件。
eclpise安装参考:eclipse安装lombok插件
idea安装参考:idea安装lombok插件
亲测了这两个都能成功。
回到正题
@ConfigurationProperties(prefix="jdbc")//读取主配置文件
@Data
public class JdbcProperties {
//所有属性名要和配置文件一样
private String driverClass;
private String url;
private String username;
private String password;
}
3、编写JdbcConfig类
@Configuration //指定为配置类
//@PropertySource("classpath:db.properties") //读取配置文件
@EnableConfigurationProperties(JdbcProperties.class)//使用JdbcProperties配置类
public class JdbcConfig {
// @Value("${jdbc.driverClass}")
// private String driverClass;
// @Value("${jdbc.url}")
// private String url;
// @Value("${jdbc.username}")
// private String username;
// @Value("${jdbc.password}")
// private String password;
// @Bean
// public DataSource getDataSource(){
// DruidDataSource dataSource = new DruidDataSource();
// dataSource.setDriverClassName(driverClass);
// dataSource.setUrl(url);
// dataSource.setUsername(username);
// dataSource.setPassword(password);
// return dataSource;
// }
@Bean //记得形参要写JdbcProperties,spring会自动传入进来
public DataSource getDataSource(JdbcProperties prop){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(prop.getDriverClass());
dataSource.setUrl(prop.getUrl());
dataSource.setUsername(prop.getUsername());
dataSource.setPassword(prop.getPassword());
return dataSource;
}
}
重启项目,此时spring容器中就有DataSource这个bean了。如果不使用形参的方式,还可以使用@AutoWired注解来进行注入,构造方法也是可以的(均不需要在JdbcProperties上加上@Component等功能的注解)
3)第三种方式
这种方式据说是最优雅,个人不习惯还是使用第二种吧。
使用场景:如果一段属性只有一个Bean需要使用,我们无需将其注入到一个类(JdbcProperties)中。而是直接在需要的地方声明即可。
@Configuration //指定为配置类
public class JdbcConfig {
@Bean
// 声明要注入的属性前缀,SpringBoot会自动把相关属性通过set方法注入到DataSource中
@ConfigurationProperties(prefix="jdbc")
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
return dataSource;
}
}
我们直接把@ConfigurationProperties(prefix = “jdbc”)声明在需要使用的@Bean的方法上,然后SpringBoot就会自动调用这个Bean(此处是DataSource)的set方法,然后完成注入。使用的前提是:该类必须有对应属性的set方法!
3. 自动配置原理简单介绍
本来不想写这个模块的,因为自己也没有深入研究,但有的地方还是有必要了解的。
回过来看启动类
@SpringBootApplication
public class WebApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(WebApplicationStarter.class, args);
}
}
主要来看看这个@SpringBootApplication注解
主要是三个注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
先看第一个@SpringBootConfiguration
其实就是个配置类,但是文档中说明了,一个应用程序只有这一个配置类,即使用一次该注解。而不像@Configuration注解可以有很多。
再看@EnableAutoConfiguration注解
根据文档得到,第二级的注解@EnableAutoConfiguration,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcat、SpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!
我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。
最后一个注解@ComponentScan
配置组件扫描的指令。提供了类似与
<
c
o
n
t
e
x
t
:
c
o
m
p
o
n
e
n
t
−
s
c
a
n
>
<context:component-scan>
<context:component−scan> 标签的作用
通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
关于默认配置就不再讲解了,因为我们的目的是熟练使用,先熟练使用了再去想原理。知道下面两个总结足够了。
1、启动器:玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器
2、全局配置:另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.properties文件来进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。因此,玩SpringBoot的第二件事情,就是通过application.properties来覆盖默认属性值,形成自定义配置。我们需要知道SpringBoot的默认属性key,非常多。
4. 补充与SMM实战
4.1. 静态资源访问
以前的web项目,访问的静态资源都放在了webapp下,现在使用spring-boot怎么访问静态资源呢?可以在resource目录下新建一个static文件夹,将静态资源放在下面。实际上前后端分离的话这种事也不用我们来做了。
页面进行访问
4.2. 拦截器
拦截器在以前使用的时候是自定义拦截器实现HandlerInterceptor,然后配置文件中进行配置。在spring-boot中怎么做呢,会更简单。
1、编写拦截器类
package com.scu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor{
private static final Logger log = LoggerFactory.getLogger(MyInterceptor.class);
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("preHandle method is running......");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("postHandle method is running......");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("afterCompletion method is running......");
}
}
补充:lombok提供的@Slfj等效于注释掉的那么创建日志对象的代码
这里跟SpringMVC写拦截器是没区别的,学习SpringMVC的时候需要在XML里面注册拦截器,在这里如何替换掉下面的xml配置呢?
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.scu.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
当然是使用Java配置了
2、编写配置类
该配置类需要实现WebMvcConfigurer接口的addInterceptors方法
@Configuration
public class MvcConfig implements WebMvcConfigurer{
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");//添加拦截器,拦截的路径
}
}
最后修改以下HelloController,添加hello方法的日志打印
@RestController
@Slf4j
public class HelloController {
@Autowired
private DataSource prop;
@GetMapping("/hello")
public String hello(){
log.info("hello method is running......");
return "hello spring-boot!";
}
}
重启项目,页面访问后查看控制台如下
4.3 配置mybatis
参照以前的spring整合mybatis配置,首先配DataSource,这里使用HikariCP数据源。接着配置SqlSessionFactoryBean。现在都只需要在application.properties这个主配置文件里面进行配置即可
具体的如下:
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
<property name="typeAliasesPackage" value="com.scu.pojo"></property>
<property name="mapperLocations" value="classpath:com.scu.mybatis.mapper"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.scu.mybatis.mapper"/>
</bean>
使用spring-boot后,先导包
<!--连接池-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
前面使用的是application.properties,这里使用以下application.yml文件(两者均可,取交集)
照着传统的配置在application.yml文件进行配置
#配置连接池D ataSource
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/e3mall_32
username: root
password: 123456
#mybatis相关配置
mybatis:
#没有myabtis的全局配置文件所以不需要去指定位置了 dataSource会自动注入
#mapper-locations: mapper/*.xml 由于使用通用mapper所以就不去指定mapper配置文件位置了
type-aliases-package: com.scu.pojo
到这里还差了一个MapperScannerConfigurer的配置,只需要在启动类上面加上@MapperScanner(“mapper路径”)即可
@SpringBootApplication
@MapperScan("com.scu.mapper")
public class WebApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(WebApplicationStarter.class, args);
}
}
4.4 通用Mapper
4.3的mybatis是没有配置完的,插播说一下通用mapper,针对单表增删改查,不需要写mapper文件了,比逆向工程还快捷。首先导入通用mapper的依赖
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
这里面是包含了jdbc和mybatis的,所以可以将4.3节中这两个依赖给删除掉。
写一个实体类User如下,与数据库e3mall_32中的tb_user表相对应,字段均相同。
@Data
public class User {
private Long id;
private String username;
private String password;
private String phone;
private String email;
private Date created;
private Date updated;
private String note;
}
写一个UserMapper接口,继承Mapper
package com.scu.mapper;
import com.scu.pojo.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User>{
}
此时UserMapper就拥有了各种常用的增删改查方法了
重新修改在启动器上加的@MapperScan对应的包,如下
import tk.mybatis.spring.annotation.MapperScan;//导入的是tk这个包的MapperScan注解
@SpringBootApplication
@MapperScan("com.scu.mapper")
public class WebApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(WebApplicationStarter.class, args);
}
}
最后还差一步,需要更改一下实体类User,使之与表关联
@Data
@Table(name="tb_user")//User类对应tb_user表
public class User {
@Id //主键
@KeySql(useGeneratedKeys=true)//得到自增的主键
private Long id;
private String username;
private String password;
private String phone;
private String email;
private Date created;
private Date updated;
@Transient//不进行持久化
private String note;
}
4.5 测试
为了让完整的项目跑起来,写个UserService如下
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryUser(Long id){//根据id查询用户信息
return userMapper.selectByPrimaryKey(id);
}
}
写个UserController如下
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("{id}")//rest风格
public User queryUser(@PathVariable("id") long id) {
return userService.queryUser(id);
}
}
重启项目,页面进行访问(使用了postman)
到这里整个项目环境就搭建完了,上面说的比较啰嗦,实际上两分钟就能完事。