1. SpringBoot框架概述
SpringBoot是对于SSM开发的一个简化,应用SpringBoot可以使我们从繁琐的写依赖、写配置的枷锁中解放出来。
它的优点有:
- 能够快速创建基于Spring的应用程序
- 能够直接使用java main方法启动内嵌的tomcat服务器运行SpringBoot程序,省去部署步骤
- 提供约定好的starter pom来简化Maven设置
- 自动化配置,根据项目的Maven依赖配置,自动配置Spring,SpringMVC等
- 提供了程序的健康检查等功能
- 基本可以不使用XML配置文件,采用注解配置
2. SpringBoot入门案例
2.1 如何创建一个SpringBoot项目
建立目录结构,创建一个处理器类:
package com.example.springboot.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class IndexController {
@RequestMapping("/SpringBoot/say")
@ResponseBody
public String say() {
return "Hello SpringBoot";
}
}
启动入口类,访问该地址即可。
2.2 核心配置文件application.properties
在此配置文件中,可用Key=Value的方式配置端口号、上下文路径等
#配置端口号
server.port=8080
#配置上下文路径
server.servlet.context-path=/springboot
则此时的访问变成了:http://localhost:8080/springboot/SpringBoot/say
配置文件以.yml或.yaml结尾也是可以的。如果与.properties的配置文件同时存在,以.properties为优先。
如果有多个以.properties结尾的配置文件,如application-xxx.properties,则在主核心配置文件application.properties中用spring.profiles.active=xxx的方式指定生效的配置文件。.yml同理
2.3 核心配置文件自定义配置
乱码问题:最好不要出现中文,如果有,则在idea-settings-editor-file encodings中勾选transparent native-to-ascii conversion即可
2.3.1 单独获取自定义配置
在核心配置文件中自定义的值,在需要该值的类中通过@Value注解就可以拿到:
#自定义配置
school.name=wuhandaxue
package com.example.springboot.web;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class IndexController {
@Value("${school.name}")
private String schoolName;
@RequestMapping("/say")
@ResponseBody
public String say() {
return "Hello" + schoolName;
}
}
2.3.2 将自定义配置映射为对象获取
要求:需要有统一的前缀
通过@Component将类交给Spring容器管理后,通过@ConfigurationProperties(prefix=“前缀”)注解获取配置文件中的自定义配置,然后通过@Resource/@Autowired自动注入:
#自定义配置
school.name=wuhandaxue
school.city=wuhan
类:
package com.example.springboot.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "school")
public class School {
private String name;
private String city;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
控制器:
package com.example.springboot.controller;
import com.example.springboot.domain.School;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
@Controller
public class IndexController {
@Resource
private School school;
@RequestMapping("/say")
@ResponseBody
public String say() {
return "Hello" + school.getName() + "in" + school.getCity();
}
}
两种获取方式可以同时使用。
@ConfigurationProperties可能会触发红色警告框,加入如下依赖即可解决:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
2.4 SpringBoot集成jsp
SpringBoot默认推荐使用的是thymeleaf,那如果要集成jsp的话,需要手动创建webapp文件夹,然后在模块设置中:
webapp文件夹多了一个蓝点即为成功,再加入jsp的解析依赖(仅支持展现功能)
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
继续在pom.xml的build标签中手动指定jsp编译的路径(springboot已规定为META-INF/resources):
<resources>
<resource>
<!--源文件夹-->
<directory>src/main/webapp</directory>
<!--指定编译到META-INF/resources-->
<targetPath>META-INF/resources</targetPath>
<!--指定哪个资源需要编译-->
<includes>
<include>*.*</include>
</includes>
</resource>
</resources>
对于jsp,我们还需要配置视图解析器来解析
#配置视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
之后jsp文件就像以前一样放在webapp中,正常步骤开发
控制器类:
package com.example.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class IndexController {
@RequestMapping("/say")
public ModelAndView say() {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "HelloJsp");
mv.setViewName("show");
return mv;
}
}
jsp:
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2021/6/7
Time: 21:48
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
3. SpringBoot的Web开发
3.1 集成Mybatis
通过mybatis提供的逆向工程xml文件和插件,来通过添加的数据库数据反向生成dao和domain(在添加依赖之前)
添加mybatis集成springboot依赖和mysql驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
加入数据到数据库
逆向工程配置文件内容:
<?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>
<!--指定连接数据库的JDBC 驱动包所在位置,指定到你本机的完整路径-->
<classPathEntry location="D:\work\maven_work\repository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar"/>
<!--配置table表信息内容体,targetRuntime 指定采用MyBatis3的版本-->
<context id="tables" targetRuntime="MyBatis3">
<!--抑制生成注释,由于生成的注释都是英文的,属性设置为true可以不让它生成-->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--配置数据库连接信息-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT"
userId="root"
password="root">
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!--生成model 类,targetPackage 指定 model 类的包名,targetProject 指定
生成的 model放在eclipse的哪个工程下面-->
<javaModelGenerator targetPackage="com.example.springboot.model"
targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="false"/>
</javaModelGenerator>
<!--生成 MyBatis的Mapper.xml文件,targetPackage 指定 mapper.xml文件的包名,targetProject 指定生成的 mapper.xml放在 eclipse的哪个工程下面
-->
<sqlMapGenerator targetPackage="com.example.springboot.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!--生成 MyBatis的 Mapper接口类文件,targetPackage 指定 Mapper 接口类的包名,targetProject 指定生成的 Mapper 接口放在eclipse 的哪个工程下面
-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.springboot.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!--数据库表名及对应的Java模型类名-->
<table tableName="t_Student" domainObjectName="Student"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false" />
<!--
<table tableName="user" domainObjectName="User"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false" />-->
</context>
</generatorConfiguration>
逆向工程插件:
<!--mybatis代码自动生成插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<!--配置文件的位置-->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
然后点击右侧Maven工具栏的生成按钮即可
编写Controller和Service,记得在mapper接口中加入@Mapper注解或选择在入口方法上加入@MapperScan,其属性指定mapper接口所在包
在核心配置文件中配置数据库连接四要素即可开启服务
3.2 事务支持
在service方法上加@Transactional注解即可
3.3 SpringBoot与SpringMVC
继承springmvc的常用注解:
- @RestController
= @Controller + @ResponseBody - @GetMapping
= @RequestMapping(method = RequestMethod.GET) - @PostMapping
= @Controller(method = RequestMethod.POST) - @PutMapping
= @Controller(method = RequestMethod.PUT) - @DeleteMapping
= @Controller(method = RequestMethod.DELETE)
3.4 实现RESTful
RESTful:一个关于路径设计的风格,路径中加入参数,如
@RequestMapping(value = “/student/detail/{id}/{age}”)
3.5 集成Redis
添加springboot集成redis的起步依赖
<!--spring集成redis的起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
编写控制器类
package com.example.springboot.web;
import com.example.springboot.service.StudentService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
@Controller
public class StudentController {
@Resource
private StudentService studentService;
@RequestMapping("/put")
@ResponseBody
public Object put(String key, String value) {
studentService.put(key, value);
return "数据插入成功!";
}
@RequestMapping("/get")
@ResponseBody
public Object get(String key) {
String value = studentService.get(key);
return "键-" + key + ",值-" + value;
}
}
编写业务方法
package com.example.springboot.service.impl;
import com.example.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class StudentServiceImpl implements StudentService {
/*
使用spring集成redis起步依赖提供的redis模板对象来操作redis数据类型,它是一个键值对类型,
泛型的key和value需要都写Object
*/
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Override
public void put(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
@Override
public String get(String key) {
return (String) redisTemplate.opsForValue().get(key);
}
}
在核心配置文件中配置redis数据库的连接信息
#设置redis配置信息
spring.redis.host=192.168.230.128
spring.redis.port=6379
3.6 集成Dubbo
3.6.1 公共包
实体类
package model;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
业务接口
package service;
import model.User;
public interface UserService {
User queryUserById(Integer id);
}
3.6.2 生产者
依赖
与Maven Dubbo项目不同,需额外注意
<dependency>
<groupId>org.example</groupId>
<artifactId>007-springboot-dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo集成springboot框架的起步依赖-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--注册中心依赖-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
接口实现类
dubbo和springboot集成后,没有了可以自定义的dubbo核心配置文件,也就无法自定义实体bean,所以需要在接口实现类中使用注解@Component的方式将其交给容器管理,不能使用@Service的原因是与后面要使用的一个同名注解冲突,所以使用@Component代替
package com.example.dubbo.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import model.User;
import org.springframework.stereotype.Component;
import service.UserService;
@Component
/*
使用alibaba.dubbo提供的注解@Service来进行自身的暴露,
属性interface, version, timeout不能少,
就如同dubbo项目中的配置文件一样
<dubbo:service interface="service.UserService" ref="userServiceImpl" version="1.0.0" timeout="15000"/>
*/
@Service(interfaceClass = UserService.class, version = "1.0.0", timeout = 15000)
public class UserServiceImpl implements UserService {
@Override
public User queryUserById(Integer id) {
User user = new User();
user.setName("池田依来沙");
user.setId(id);
return user;
}
}
核心配置文件
在核心配置文件中,生产者需要走三步:声明自身、声明注册中心、表明自身身份。
而声明注册中心和暴露自身的语句都没有idea的自动补全,需要熟记
#设置端口号和上下文根
#此步设置是必须的,因为后面要同时启动两个tomcat,如果不改端口号,势必会冲突
server.port=8081
server.servlet.context-path=/
#设置dubbo
#声明自己
spring.application.name=008-springboot-dubbo-provider
#声明注册中心
spring.dubbo.registry=zookeeper://localhost:2181
#表明自身身份
spring.dubbo.server=true
3.6.3 消费者
依赖
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>007-springboot-dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
控制器方法
package com.example.dubbo.web;
import com.alibaba.dubbo.config.annotation.Reference;
import model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import service.UserService;
@Controller
public class UserController {
/*
没有配置文件声明实体bean,控制器方法也就不能使用@Autowired/@Resource来进行自动赋值了,
需要使用alibaba.dubbo提供的注解@Reference来指明引用,
属性interface, version, check不能少,
就如同dubbo项目中的配置文件一样
<dubbo:reference id="userService" interface="service.UserService" version="1.0.0" check="false"/>
*/
@Reference(interfaceClass = UserService.class, version = "1.0.0", check = false)
private UserService userService;
@RequestMapping("/userDetail")
@ResponseBody
public Object userDetail(Integer id) {
User user = userService.queryUserById(id);
return "res" + user;
}
}
核心配置文件
#配置dubbo
#声明自己
spring.application.name=009-springboot-dubbo-consumer
#声明注册中心
spring.dubbo.registry=zookeeper://localhost:2181
3.6.4 启动入口方法
因为在dubbo集成springboot项目中使用了多种dubbo提供的注解,而入口方法默认提供的注解@SpringBootApplication只能对springboot注解生效,所以我们需要在入口方法上加入专门使dubbo注解生效的@EnableDubboConfiguration,来开启dubbo配置。
生产者和消费者都需要。
package com.example.dubbo;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubboConfiguration //用于开启dubbo的注解和配置
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3.7 springboot-dubbo-redis-mybatis大集合
配合逆向工程文件和逆向插件,来生成实体类和dao层
3.7.1 公共包
实体类由逆向工程自动生成
实体类
package com.example.springboot.model;
import java.io.Serializable;
public class Student implements Serializable {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
业务接口
package com.example.springboot.service;
import com.example.springboot.model.Student;
public interface StudentService {
Student queryStudentById(Integer id);
int getStudentCount();
}
3.6.2 生产者
依赖
与Maven Dubbo项目不同,需额外注意
既然是大集合,就需要有springboot起动依赖, dubbo, redis, mybatis, mysql驱动, zookeeper和公共包接口依赖,因为了dao层的xml映射文件,所以还需要扫描插件告诉idea将其一同编译到classes中去。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>010-springboot-dubbo-redis-ssm-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<!--mybatis代码自动生成插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<!--配置文件的位置-->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
接口实现类
@Resource和@Autowired都可以
package com.example.springboot.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.example.springboot.mapper.StudentMapper;
import com.example.springboot.model.Student;
import com.example.springboot.service.StudentService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Component
@Service(interfaceClass = StudentService.class, version = "1.0.0", timeout = 15000)
public class StudentServiceImpl implements StudentService {
@Resource
private StudentMapper studentMapper;
@Resource
private RedisTemplate<Object, Object> redisTemplate;
@Override
public Student queryStudentById(Integer id) {
return studentMapper.selectByPrimaryKey(id);
}
@Override
public int getStudentCount() {
//首先去redis缓存中查询,redis中没有再去数据库查,然后放到redis中
Integer totalCount = (Integer) redisTemplate.opsForValue().get("count");
if (totalCount == null) {
totalCount = studentMapper.getStudentTotalCount();
//可选择设置数据存活时间
redisTemplate.opsForValue().set("totalCount", totalCount, 15, TimeUnit.SECONDS);
}
return totalCount;
}
}
核心配置文件
redis在linux中启动,所以ip为linux的
#设置端口号和上下文根
server.port=8081
server.servlet.context-path=/
#设置dubbo
spring.application.name=011-springboot-dubbo-redis-ssm-provider
spring.dubbo.server=true
spring.dubbo.registry=zookeeper://localhost:2181
#设置mybatis
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=root
#设置redis
spring.redis.host=192.168.230.128
spring.redis.port=6379
3.6.3 消费者
消费者则需要springboot起动依赖, dubbo, zookeeper, jsp展现和公共包接口依赖。同时需要告诉idea将jsp文件一同编译到classes中去,所以需要编译的插件
依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>010-springboot-dubbo-redis-ssm-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<!--源文件夹-->
<directory>src/main/webapp</directory>
<!--指定编译到META-INF/resources-->
<targetPath>META-INF/resources</targetPath>
<!--指定哪个资源需要编译-->
<includes>
<include>*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
控制器方法
package com.example.springboot.web;
import com.alibaba.dubbo.config.annotation.Reference;
import com.example.springboot.model.Student;
import com.example.springboot.service.StudentService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class StudentController {
@Reference(interfaceClass = StudentService.class, version = "1.0.0", check = false)
private StudentService studentService;
@RequestMapping("/student")
public String studentDetail(Model model, Integer id) {
Student student = studentService.queryStudentById(id);
model.addAttribute("student", student);
return "studentDetail";
}
@RequestMapping("/studentCount")
@ResponseBody
public Object studentCount(Model model) {
int count = studentService.getStudentCount();
return "总人数:" + count;
}
}
核心配置文件
#设置dubbo
spring.application.name=012-springboot-dubbo-redis-ssm-consumer
spring.dubbo.registry=zookeeper://localhost:2181
#配置视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
3.6.4 启动入口方法
生产者
@MapperScan用来统一扫描mapper包,就不用在mapper接口一个个加了。
package com.example.springboot;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubboConfiguration
@MapperScan(basePackages = "com.example.springboot.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
消费者
package com.example.springboot;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubboConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. SpringBoot非Web应用程序
本章了解即可。
4.1 第一种方法
在springboot程序启动后,会返回一个spring容器ConfigurableApplicationContext,类似于以前的spring容器ClasspathXmlApplicationContext。
可在入口方法中声明它,来获得容器中的bean
ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
StudentService service = (StudentService)applicationContext.getBean("studentServiceImpl");
4.2 第二种方法
通过实现CommandLineRunner接口的方式来执行
@SpringBootApplication
@EnableDubboConfiguration
public class Application implements CommandLineRunner {
@Resource
private StudentService studentService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
studentService.method();
}
}
5. SpringBoot使用拦截器
手写拦截器实现HandlerInterceptor接口,由于在springboot中无法配置拦截器,代替它的是创建拦截器配置类并在其类名上加入@Configuration注解使其相当于一个xml配置文件,再实现WebMvcConfigurer接口,重写它的addInterceptors方法。
addInterceptors方法自带一个形参InterceptorRegistry,使用形参的addInterceptor()方法来注册拦截器和拦截路径
实体类
package com.example.springboot.model;
public class User {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
拦截器类
package com.example.springboot.interceptor;
import com.example.springboot.model.User;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = (User) request.getSession().getAttribute("user");
if (user == null) {
response.sendRedirect(request.getContextPath() + "/user/login");
return false;
}
return true;
}
}
拦截器配置类
package com.example.springboot.config;
import com.example.springboot.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/*
由于在springboot中无法配置拦截器,
代替它的是创建拦截器配置类并在其类名上加入@Configuration注解使其相当于一个xml配置文件,
再实现WebMvcConfigurer接口,重写它的addInterceptors方法。
addInterceptors方法自带一个形参InterceptorRegistry,
使用形参的addInterceptor()方法来注册拦截器和拦截路径
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
//类似于配置文件中的<mvc:interceptors>
@Override
public void addInterceptors(InterceptorRegistry registry) {
//要拦截的路径
String[] addPathPatterns = {"/user/**"};
//要放行的路径,多个路径以,隔开
String[] excludePathPatterns = {"/user/login"};
//类似于<bean class="handler.Interceptor"/>
registry.addInterceptor(new MyInterceptor()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
}
}
控制器
package com.example.springboot.web;
import com.example.springboot.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
@ResponseBody
public Object login(HttpServletRequest request) {
User user = new User();
user.setId(1001);
user.setName("池田依来沙");
request.getSession().setAttribute("user", user);
return "login success!";
}
@RequestMapping("/center")
@ResponseBody
public Object center() {
return "access to center!";
}
}
6. SpringBoot使用Servlet
本章了解即可。
第一种方式:
自定义一个servlet继承HttpServlet,重写doGet(), doPost()方法,在类上加入@WebServlet注解,属性定义请求uri,在入口方法上加入@ServletComponentScan注解,属性basePackages设为servlet包的路径即可。
第二种方式:
用创建配置类(注册组件)的方式代替注解,在类上加入@Configuration注解,创建返回值为ServletRegistryBean的方法,在方法上加入@Bean,它相当于bean标签,在方法体中new出这个对象,将自己创建的servlet,请求路径传参即可。
7. SpringBoot使用Filter/Listener
本章了解即可。
7.1 Filter
第一种方式:
创建过滤器类,实现javax.servlet.filter接口,类名上加入@WebFilter注解,用属性声明要过滤的url-pattern,最后在入口方法上加入@ServletComponentScan注解,属性basePackages设为filter包的路径即可。
第二种方式:
创建过滤器类,实现javax.servlet.filter接口,用创建配置类(注册组件)的方式代替注解,在类上加入@Configuration注解,创建返回值为FilterRegistryBean的方法,在方法上加入@Bean,它相当于bean标签,在方法体中new出这个对象,将自己创建的filter传参,再用该对象调用addUrlPatterns,将要过滤的路径(不支持**)以字符串形式传参即可。
7.2 Listener
创建监听器类,实现javax.servlet.ServletContextListener接口,实现它的初始化或销毁方法,之后在类上加入@Component注解
@Component
public class DicListener implements ServletContextListener {
@Reference(interfaceClass = DicService.class, version = "1.0.0")
private DicService dicService;
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("开始加入数据字典");
ServletContext servletContext = sce.getServletContext();
Map<String, List<DicValue>> map = dicService.getAll();
Set<String> set = map.keySet();
for (String s : set) {
List<DicValue> list = map.get(s);
servletContext.setAttribute("s" + list, list);
}
System.out.println("完成加入数据字典");
}
}
8. SpringBoot项目配置字符编码
字符编码过滤器类characterEncoding容器已经帮我们写好了,我们直接拿来。
创建该过滤器类,然后使用它的setForceEncoding()方法,传参true,再用它的setEncoding()方法传参要使用的编码集。
然后用创建配置类(注册组件)的方式代替注解,在类上加入@Configuration注解,创建返回值为FilterRegistryBean的方法,在方法上加入@Bean,它相当于bean标签,在方法体中new出这个对象,用该对象的setFilter()方法将写好的字符过滤器类传参,再用该对象调用addUrlPatterns,将要过滤的路径(不支持**)以字符串形式传参。
最后,在spring核心配置文件中关闭springboot自带的http字符编码支持,我们的才能生效。
spring.http.encoding.enabled=false
server.servlet.encoding.enabled=false
备选:resp.setContentType("text/html;character=utf-8");
第二种方式:
仅在spring核心配置文件中配置:
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.http.encoding.charset=utf-8
9. SpringBoot打包与部署
记得手动指定资源文件夹
<resources>
<resource>
<!--源文件夹-->
<directory>src/main/webapp</directory>
<!--指定编译到META-INF/resources-->
<targetPath>META-INF/resources</targetPath>
<!--指定哪个资源需要编译-->
<includes>
<include>*.*</include>
</includes>
</resource>
</resources>
还有,如果没有这个,打好的包中是没有资源文件夹的。
<resources>
<resource>
<!--源文件夹-->
<directory>src/main/resources</directory>
<!--指定哪个资源需要编译-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
9.1 打war包
在pom.xml文件中通过<packaging>
标签填入war,来指定打成war包,在<build>
中用<finalName>
指明项目名,再让入口方法继承SpringBootServletInitializer,重写它的configure()方法,返回值设为build.sources(Application.class);
即可,之后将war包放入tomcat的webapp文件夹中就算部署成功,使用项目名+路径就可以访问了。
要注意的是,打war包的方式中,写在配置文件中的视图解析器是无效的,因为你换了个服务器运行。
9.2 打jar包
无需packaging指定,自动打成jar包,可在<build>
中用<finalName>
指明项目名。
打jar包的方式可以通过在cmd中用java命令的方式启动服务器来访问,因为springboot有内置的tomcat,此时,配置文件中的设置是会生效的。
10. 集成logback日志
该依赖springboot自带。
在resources目录中创建,起名要求为logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为 TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果
设置为 WARN,则低于 WARN 的信息都不会输出 -->
<!-- scan:当此属性设置为 true 时,配置文件如果发生改变,将会被重新加载,默认值为
true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认
单位是毫秒。当 scan 为 true 时,此属性生效。默认的时间间隔为 1 分钟。 -->
<!-- debug:当此属性设置为 true 时,将打印出 logback 内部日志信息,实时查看 logback
运行状态。默认值为 false。通常不打印 -->
<configuration scan="true" scanPeriod="10 seconds">
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志 appender 是为开发使用,只配置最底级别,控制台输出的日志级别是大
于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>%date [%-5p] [%thread] %logger{60} [%file : %line] %msg%n</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--<File>/home/log/stdout.log</File>-->
<File>D:/log/stdout.log</File>
<encoder>
<pattern>%date [%-5p] %thread %logger{60} [%file : %line] %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 添加.gz 历史日志会启用压缩 大大缩小日志文件所占空间 -->
<!--<fileNamePattern>/home/log/stdout.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
<fileNamePattern>D:/log/stdout.log.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory><!-- 保留 30 天日志 -->
</rollingPolicy>
</appender>
<logger name="com.abc.springboot.mapper" level="DEBUG" />
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
如果需要在控制器中手动打印日志,那么就要加入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
然后在类名上加@Slf4j注解,加入lombok插件,再使用log.trace/debug/info/warn/error()方法来输出自定义日志。
11. 集成Thymeleaf模板
11.1 什么是Thymeleaf
一个Java语言开发的流行的模板引擎,对网络环境无严格要求,既可用于web环境,也可用于非web环境。它需要寄托在Html标签下才能实现。SpringBoot已经继承了Thymeleaf模板,所有的html都应写在templates中,这个文件夹中的文件无法被地址栏直接访问,必须经过中央调度器。
在web环境下,可以像jsp一样从后台接收数据并替换掉模板上的静态数据
在非web环境下,能直接显示模板上的静态数据
thymeleaf不需要像jsp一样要先编译后渲染,它的文件自始至终都是html文件,这样的模板引擎最终可以达成前后端分离的效果,提升用户体验。
11.2 SpringBoot集成Thymeleaf
创建带有Thymeleaf模板的springboot工程的过程有些许不同,在勾选Spring Web工程之后,还需要勾选:
在templates文件夹中新建的html中加入命名空间:xmlns:th="http://www.thymeleaf.org"
,在html标签中加入th:text="xxx"
的属性,即可拿到后台的数据。如果有则替换掉静态数据,如果没有就展现静态数据:
特殊情况下,html文件位置变动了,可更改视图解析器的默认配置来匹配最新的html文件的位置。
thymeleaf的缓存默认是开启的,我们将其设置为关闭,再将服务器的“后台文件变化时”从do nothing改为自动更新资源,即可热更新前台显示
前端页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:text="${user.id}">xxx</div>
<div th:text="${user.name}">xxx</div>
</body>
</html>
配置文件
spring.thymeleaf.cache=false
11.3 Thymeleaf的表达式
11.3.1 标准变量表达式
${}
标准变量表达式用于访问容器(tomcat)上下文环境中的变量,功能和EL表达式的${}相同。
必须放在html标签中,以th:text="${xxx}"
包裹
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:text="${user.id}">xxx</div>
<div th:text="${user.name}">xxx</div>
</body>
</html>
11.3.2 选择变量表达式
不推荐。
使用th:object="${xxx}"
属性来绑定对象,在其子标签中就可以使用*{id}
的方式来代替${xxx.id}
11.3.3 混合使用
不推荐。
放在html标签中,直接以th:text="*{xxx}"
包裹拿到数据,不需要th:object="${xxx}"
11.3.4 url路径表达式
11.3.4.1 不带参数:无优化
绝对路径:
传统写法:<a href="http://www.baidu.com"></a>
表达式写法:<a th:href="@{http://www.baidu.com}"></a>
相对路径:
传统写法:<a href="/res">传统方式相对路径跳转到res</a>
表达式写法:<a th:href="@{/res}">thymeleaf相对路径跳转到res</a>
11.3.4.2 自带参数:无优化
传统写法:
<a href="/param?username=池田依来沙&height=170">带参数跳转</a>
表达式写法:
<a th:href="@{/param?username=池田依来沙&height=170}">thymeleaf方式带参数跳转</a>
11.3.4.3 从后台获取参数
无传统写法,只有依靠jsp或者thymeleaf写法
传统写法:依靠jsp
表达式写法:
<a th:href="@{'/param?username=' + ${user.name}}">thymeleaf方式从后台获取参数然后带参数跳转</a>
当有多个参数时,不用非常麻烦的拼接,使用表达式写法会非常方便
<a th:href="@{/param(id=${user.id},name=${user.name})}">thymeleaf方式从后台获取多个参数然后带参数跳转</a>
11.3.4.4 引用静态资源:无优化
对于静态资源的引用,使用thymeleaf包裹,如:
<script type="text/javascript" th:src="@{/js/jquery-x.x.x.min}"></script>
<img th:src="@{/img/001.jpg}">
11.4 Thymeleaf的常见属性
一般从后台取来的数据所在的标签的属性前加th:即可用到thymeleaf的功能,如
表单中的action=
->th:action
11.4.1 循环遍历List集合
完整版:th:each="user,userStat:${userList}"
其实可以将userStat省略,即使省略也可以在标签内部使用它
th:each="user:${userList}"
其中,user代表从userList中拿出来的每一个元素即当前循环的对象,在子标签中对user进行展示即可。userStat代表当前循环对象的状态,可用userStat.的方式得到一些状态变量。userList代表被循环的集合。
<div th:each="user:${userList}">
<span th:text="${user.id}"></span>
<span th:text="${user.name}"></span>
</div>
11.4.2 循环遍历Map集合
<div th:each="user:${userMap}">
<span th:text="${user.getKey()}"></span>
<span th:text="${user.getValue().id}"></span>
<span th:text="${user.getValue().name}"></span>
</div>
11.4.3 循环遍历Array集合
同List一样
11.4.4 复杂的循环遍历
list套map套list装user
<div th:each="a:${complicatedList}">
<div th:each="b:${a}">
<div th:each="c:${b.getValue()}">
<span th:text="${c.id}"></span>
<span th:text="${c.name}"></span>
</div>
</div>
</div>
11.4.5 条件判断
th:if
th:if=“${sex eq 1}”:等于1就显示
th:unless
th:unless=“${sex eq/ne 1}”:等于1就不显示/不等于1就不显示
th:switch/th:case
th:switch=“${productType}”
th:case=“0”
th:case=“*”
11.4.6 内敛表达式
在父级标签加th:inline=“xxx”,xxx可取text,javascript和none
11.4.6.1 内敛文本
内敛文本表达式不依赖于html,在子标签域中(域外也行)直接使用内敛表达式[[表达式]]即可获取动态数据,但必须要求在父级标签上加th:inline="text"属性,所以可以写在body里
<div th:inline="text">
数据:[[${data}]]
</div>
11.4.6.2 内敛脚本
在script中想取值,需要在script标签上加内敛脚本,然后在[[]]中获得
<script type="text/javascript" th:inline="javascript">
function showData() {
alert([[${data}]]);
}
</script>
11.4.6.3 值为none则什么都不做
11.5 Thymeleaf字面量
跟在th表达式中的
文本字面量:'xxx'
/"xxx"
数字字面量:"2020"
布尔字面量:"${flag}"
空值字面量:``
11.6 Thymeleaf字符串拼接
使用|xxx|来包裹要拼接的字符串,如
<span th:text="|共${totalRows}条${totalPages}页,当前第${currentPage}页|">共123条13页,当前第2页</span>
显示效果就是
共123条13页,当前第2页
11.7 Thymeleaf运算符
在th:text="${}"
的引号中使用
三元运算:表达式?”正确结果”:”错误结果”
算术运算:+ , - , * , / , %
关系比较::> , < , >= , <= ( gt , lt , ge , le )
相等判断:== , != ( eq , ne )
11.8 Thymeleaf表达式基本对象
模板引擎提供了一组内置的对象,这些内置的对象可以直接在模板中使用,这些对象由
#号开始引用,我们比较常用的内置对象#request(相当于#httpServletRequest)、#session
手动指定上下文根
<script type="text/javascript" th:inline="javascript">
var basePath = [[${#httpServletRequest.getScheme() + "://" +
#httpServletRequest.getServerName() + ":" +
#httpServletRequest.getServerPort() +
#httpServletRequest.getContextPath()}]];
//http://localhost:8080/springboot/user/login
//获取协议名称
var scheme = [[${#request.getScheme()}]];
//获取服务 IP 地址
var serverName = [[${#request.getServerName()}]];
//获取服务端口号
var serverPort = [[${#request.getServerPort()}]];
//获取上下文根
var contextPath = [[${#request.getContextPath()}]];
var allPath = scheme+"://"+serverName+":"+serverPort+contextPath;
alert(allPath);
</script>
从session中获取数据的三种方式
<span th:text="${#session.getAttribute('username')}"></span><br/>
<span th:text="${#httpSession.getAttribute('username')}"></span><br/>
<span th:text="${session.username}"></span>
获得地址栏url:
#request.requestURL
获得传递的参数:
#request.queryString
11.9 Thymeleaf表达式功能对象(了解)
模板引擎提供的一组功能性内置对象,可以在模板中直接使用这些对象提供的功能方法
工作中常使用的数据类型,如集合,时间,数值,可以使用 Thymeleaf 的提供的功能性对象来处理它们
内置功能对象前都需要加#号,内置对象一般都以 s 结尾
官方手册:http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
#dates: java.util.Date 对象的实用方法:
<span th:text="${#dates.format(curDate, 'yyyy-MM-dd HH:mm:ss')}"></span>
#calendars: 和 dates 类似, 但是 java.util.Calendar 对象;
#numbers: 格式化数字对象的实用方法;
#strings: 字符串对象的实用方法: contains, startsWith, prepending/appending 等;
#objects: 对 objects 操作的实用方法;
#bools: 对布尔值求值的实用方法;
#arrays: 数组的实用方法;
#lists: list 的实用方法,比如<span th:text="${#lists.size(datas)}"></span>
#sets: set 的实用方法;
#maps: map 的实用方法;
#aggregates: 对数组或集合创建聚合的实用方法;
12 部署linux
12.1 启动zookeeper
记得更改配置文件
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=D:\work\zookeeper\apache-zookeeper-3.5.9-bin\apache-zookeeper-3.5.9-bin\data
# the port at which the clients will connect
clientPort=2181
admin.serverPort=8888
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
安装解压缩zookeeper:tar -zxvf xxx -C xxx
zookeeper启动:在bin目录下执行 ./zkServer.sh start
zookeeper关闭:在bin目录下执行 ./zkServer.sh stop
12.2 启动Mysql
mysql启动:在bin目录下执行 ./mysqld_safe &
mysql关闭:在bin目录下执行 ./mysqladmin -uroot -p shutdown
再输入密码回车即可
12.3 启动生产者
在jar所在目录中执行java -jar xxx.jar &
12.4 启动消费者
在jar所在目录中执行java -jar xxx.jar &
13 我遇到的问题
问题描述:无法通过index.html跳转到login.html
解决方案:发现到index.html中跳转的路径是直接修改地址栏的地址来实现访问的,而springboot所有的html文件都在templates下,这个文件夹下的文件无法通过地址栏直接访问,所以将index.html中的访问方式改为通过后台访问,这样就可以通过中央调度器,然后通过后台转发到login.html即可解决。或者通过在配置文件中配置spring.web.resources.static-locations=classpath:/templates/,classpath:/static/
的方式解除静态资源的访问也可以。
问题描述:无法访问静态资源,错误404,target中已编译
解决方案:static中的静态文件springboot可以直接读取,所以将静态资源前的/static或者…/static去掉,重启服务器即可。
记得序列化
要想在某个html中使用thymeleaf,该html必须是由后台返回的视图跳转的
每一个由后台视图返回的html都加上
<base th:href="${#httpServletRequest.getScheme() + '://' +
#httpServletRequest.getServerName() + ':' +
#httpServletRequest.getServerPort() +
#httpServletRequest.getContextPath()}">
之后再编辑
templates下的子包中的html发起的请求,需在接收请求的控制器类的请求路径字符串前加上完整包名