SpringBoot
SpringBoot简介
-
- 创建独立Spring应用
-
- 内嵌web服务器
-
- 自动starter依赖,简化构建配置
-
- 自动配置Spring以及第三方功能
-
- 提供生产级别的监控、健康检查及外部化配置
-
- 无代码生成、无需编写XML
SpringBoot是整合Spring技术栈的一站式框架
SpringBoot是简化Spring技术栈的快速开发脚手架
SpringBoot缺点
- 人称版本帝,迭代快,需要时刻关注变化
- 封装太深,内部原理复杂,不容易精通
第一个SpringBoot项目
pom.xml文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--当前项目的父工程GAV-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--当前项目的GAV-->
<groupId>com.ning.springboot</groupId>
<artifactId>001-springboot-first</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<!--依赖-->
<dependencies>
<!--SpringBoot项目起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot项目测试起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!--SpringBoot项目编译打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SpringBoot 主程序
/**
* 主程序类
* @SpringBootApplication:这是一个SpringBoot应用
* 写的业务代码必须放在 Application类所在的同级目录或者下级目录
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
}
SpringBoot 核心文件
Spring Boot的核心配置文件用于配置Spring Boot程序,名字必须以application开始
1、application.properties (默认采用)
键值对的properties属性文件配置方式
#设置内嵌tomcat 端口号
server.port=8081
#设置上下文根
server.servlet.context-path=/springboot
# 原本的访问路径: localhost:8080
# 设置完成以后的访问路径: localhost:8081/springboot
2、yaml / yml
1、简介:
YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet
Another Markup Language"(仍是一种标记语言)。非常适合用来做以数据为中心的配置文件
2、基本语法
-
key: value;kv之间有空格
-
大小写敏感
-
使用缩进表示层级关系
-
缩进不允许使用tab,只允许空格
-
缩进的空格数不重要,只要相同层级的元素左对齐即可
-
'#'表示注释
-
字符串无需加引号,如果要加,’'与""表示字符串内容 会被 转义/不转义
-
大家如果是从其它地方拷贝的配置文件,一定要将里面的空格删干净
3、数据类型
1、字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
2、对象:键值对的集合。map、hash、set、object
行内写法: k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
3、数组:一组按次序排列的值。array、list、queue
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
4、整合写法
# yaml表示以上对象
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
SpringBoot 多环境配置
在实际开发的过程中,我们的项目会经历很多的阶段(开发->测试->上线),每个阶段的配置也会不同,例如:端口、上下文根、数据库
等,那么这个时候为了方便在不同的环境之间切换,SpringBoot提供了多环境配置,具体步骤如下:
为每个环境创建一个配置文件,命名必须以application-环境标识.properties|yml
1、application-dev.properties
#开发环境
#设置内嵌Tomcat默认端口号
server.port=8080
#设置项目的上下文根
server.servlet.context-path=/006-springboot-multi-environment-dev
2、application-product.properties
#生产环境
#配置内嵌Tomcat默认端口号
server.port=80
#配置项目上下文根
server.servlet.context-path=/006-springboot-multi-environment-product
3、application-test.properties
#测试环境
#配置内嵌Tomcat端口号
server.port=8081
#配置项目的上下文根
server.servlet.context-path=/006-springboot-multi-environment-test
application.properties (在总配置文件application.properties进行环境的激活)
#SpringBoot的总配置文件
#激活开发环境
#spring.profiles.active=dev
#激活测试环境
#spring.profiles.active=test
#激活生产环境
spring.profiles.active=product
两个注解的使用
@Value
在核心配置文件applicatin.properties中,添加两个自定义配置项school.name和school.website。在IDEA中可以看到这两个属性不能被
SpringBoot识别,背景是桔色的
#核心配置文件
school.name=bjpowernode
school.website=www.bjpoergr
# controller 文件
@Value("${school.name}")
private String schoolName;
@Value("${school.website}")
@RequestMapping(value = "/say2")
public @ResponseBody String say2() {
return schoolName + "------" + schoolWebsite;
}
private String schoolWebsite;
@ConfigurationProperties
在com.ning.springboot.config包下创建ConfigInfo类,并为该类加上Component和ConfigurationProperties注解,prefix可以不
指定,如果不指定,那么会去配置文件中寻找与该类的属性名一致的配置,prefix的作用可以区分同名配置
############################################################################################
# 实体类
@Component
@ConfigurationProperties(prefix = "school")
public class ConfigInfo {
private String name;
private String websit;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWebsit() {
return websit;
}
public void setWebsit(String websit) {
this.websit = websit;
}
}
############################################################################################
# controller
@Autowired
private ConfigInfo configInfo;
@RequestMapping(value = "/springBoot/configInfo")
public @ResponseBody String say() {
return configInfo.getName() + "=======" + configInfo.getWebsit();
}
############################################################################################
# 核心配置文件
school.name=bjpowernode
school.website=www.bjpoergr
<!--解决使用@ConfigurationProperties注解出现警告问题-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
SpringBoot 中使用jsp (一般情况不用)
1、pom.xml文件中添加依赖
<!--引入Spring Boot内嵌的Tomcat对JSP的解析包,不加解析不了jsp页面-->
<!--如果只是使用JSP页面,可以只添加该依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--如果要使用servlet必须添加该以下两个依赖-->
<!-- servlet依赖的jar包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!-- jsp依赖jar包-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!--如果使用JSTL必须添加该依赖-->
<!--jstl标签依赖的jar包start-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!--在pom.xml的build标签中要配置以下信息-->
<!--
SpringBoot要求jsp文件必须编译到指定的META-INF/resources目录下才能访问,否则访问不到。
其它官方已经建议使用模版技术(后面会课程会单独讲解模版技术)
-->
<resources>
<resource>
<!--源文件位置-->
<directory>src/main/webapp</directory>
<!--指定编译到META-INF/resource,该目录不能随便写-->
<targetPath>META-INF/resources</targetPath>
<!--指定要把哪些文件编译进去,**表示webapp目录及子目录,*.*表示所有文件-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
2、在application.properties文件配置Spring MVC的视图展示为jsp,这里相当于Spring MVC的配置
#配置SpringMVC的视图解析器
#其中:/相当于src/main/webapp目录
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
剩下的跟ssm框架一样了
SPringBoot 集成 Mybatis
Mybatis逆向工程
1、在项目的根目录下创建 GeneratorMapper.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>
<!-- 指定连接数据库的JDBC驱动包所在位置,指定到你本机的完整路径 -->
<classPathEntry location="D:\mysql-connector-java-8.0.22.jar"/>
<!-- 配置table表信息内容体,targetRuntime指定采用MyBatis3的版本 -->
<context id="tables" targetRuntime="MyBatis3">
<!-- 抑制生成注释,由于生成的注释都是英文的,可以不让它生成 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 配置数据库连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/spring_boot?serverTimezone=UTC"
userId="root"
password="123456">
</jdbcConnection>
<!-- 生成实体类,targetPackage指定实体类的包名, targetProject指定生成的model放在eclipse的哪个工程下面-->
<javaModelGenerator targetPackage="com.ning.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.ning.springboot.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- 生成MyBatis的Mapper接口类文件,targetPackage指定Mapper接口类的包名, targetProject指定生成的Mapper接口 放在eclipse的哪个工程下面 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.ning.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"/>
</context>
</generatorConfiguration>
2、在pom.xml文件中添加mysql反向工程依赖
<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>
自动生成的 文件解析
/****************************************************************************************************/
// 实体类
package com.ning.springboot.model;
public class Student {
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;
}
}
/****************************************************************************************************/
// dao接口
package com.ning.springboot.mapper;
import com.ning.springboot.model.Student;
public interface StudentMapper {
int deleteByPrimaryKey(Integer id);
int insert(Student record);
int insertSelective(Student record);
Student selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(Student record);
int updateByPrimaryKey(Student record);
}
/****************************************************************************************************/
// 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.ning.springboot.mapper.StudentMapper">
<!--
数据库表字段名称 实体类对象属性名称
user_name userName
userage userage
userName username
如果数据库中字段名称由多个单词构成,通过mybatis逆行工程生成的对象属性名称会按照驼峰命名法生成对应的属性名称
其中:字段名称由多个单词构成 必须要用 _ 下划线隔开
-->
<!--
resultMap 作用:
1、当数据库中字段名称与实体类对象的属性名不一致时,可以进行转换
2、当前查询的结果没有对应一个表时,可以自定义结果集。
-->
<!-- id 字段只能修改主键字段-->
<!-- result 除了主键以外的字段-->
<!--
column: 数据库中的字段名称
jdbcType: 数据库中字段的类型(可忽略不写)
property: 映射对象的属性名称
-->
<resultMap id="BaseResultMap" type="com.ning.springboot.model.Student">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
</resultMap>
<!--
sql语句片段,将公共的部分抽取出来
通过 include 标签引用sql语句片段
-->
<sql id="Base_Column_List">
id, name, age
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_student
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from t_student
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.ning.springboot.model.Student">
insert into t_student (id, name, age
)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}
)
</insert>
<!--
suffixOverrides="," : 去除多余的 , 号
-->
<insert id="insertSelective" parameterType="com.ning.springboot.model.Student">
insert into t_student
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
name,
</if>
<if test="age != null">
age,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="age != null">
#{age,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.ning.springboot.model.Student">
update t_student
<set>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="age != null">
age = #{age,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.ning.springboot.model.Student">
update t_student
set name = #{name,jdbcType=VARCHAR},
age = #{age,jdbcType=INTEGER}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
SpringBoot集成MyBatis 基本步骤
1、创建springboot项目 ,加入·缺少的依赖
<!--MyBatis整合SpringBoot的起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--MySQL的驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--添加mysql反向工程依赖-->
<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>
<!--在build标签中 手动指定文件解析 dao接口映射文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
2、在Springboot的核心配置文件application.properties中配置数据源
#配置数据库的连接信息
#注意这里的驱动类有变化
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
3、使用mybatis逆向工程生成实体类和 (dao 接口 加 @Mapper 注解)和响应的映射文件
/***************************************************************************************************/
// dao接口
package com.ning.springboot.mapper;
import com.ning.springboot.model.Student;
import org.apache.ibatis.annotations.Mapper;
@Mapper // 扫描 dao 接口到 spring 容器
public interface StudentMapper {
int deleteByPrimaryKey(Integer id);
int insert(Student record);
int insertSelective(Student record);
Student selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(Student record);
int updateByPrimaryKey(Student record);
}
3.1 运行的主类上添加注解包扫描@MapperScan(“com.ning.springboot.mapper”) ,注释掉StudentMapper接口上的@Mapper注解 ,其他不变
// SpringBoot主程序入口
package com.ning.springboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @MapperScan : 作用
* 扫描 dao 接口到 spring 容器
* 不用在 每一个 mapper 接口中 添加 @Mapper 注解
* basePackages 可以省略
*
*/
@SpringBootApplication
@MapperScan(basePackages = "com.ning.springboot.mapper") // 开启扫描mapper接口的包以及子目录
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、编写sercive
package com.ning.springboot.service;
import com.ning.springboot.model.Student;
public interface StudentService {
Student queryStudentById(Integer id);
}
5、service接口实现类 加==@Service== 注解
package com.ning.springboot.service.impl;
import com.ning.springboot.mapper.StudentMapper;
import com.ning.springboot.model.Student;
import com.ning.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public Student queryStudentById(Integer id) {
return studentMapper.selectByPrimaryKey(id);
}
}
6、controller业务代码
package com.ning.springboot.controller;
import com.ning.springboot.model.Student;
import com.ning.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("/student")
@ResponseBody
public Object School(Integer id){
Student student = studentService.queryStudentById(id);
return student;
}
}
Mapper文件存放位置
1、dao接口和dao接口映射文件在同一个文件夹中
<!--只需要在pom.xml文件中添加-->
<!--在build标签中 手动指定文件解析 dao接口映射文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
2、接口和映射文件位置分开
# 在 application.properties 文件中添加配置
# 指定MyBatis文件的映射文件路径
mybatis.mapper-locations=classpath:mapper/*.xml
事务
SpringBoot 使用事务非常简单,底层依然采用的是Spring本身提供的事务管理
在入口类中使用注解 @EnableTransactionManagement 开启事务支持
在访问数据库的Service方法上添加注解 @Transactional 即可
只有在 增删改的时候需要事务
1、在访问数据库的Service方法上添加注解 @Transactional 即可
package com.ning.springboot.service.impl;
import com.ning.springboot.mapper.StudentMapper;
import com.ning.springboot.model.Student;
import com.ning.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
public class StudentServiceImpl implements StudentService {
@Resource
private StudentMapper studentMapper;
@Override
@Transactional //添加此注解说明该方法添加的事务管理 这个注解必须添加
public int update(Student student) {
int updateCount = studentMapper.updateByPrimaryKeySelective(student);
//在此构造一个除数为0的异常,测试事务是否起作用
int a = 10/0;
return updateCount;
}
}
2、在入口类中使用注解 @EnableTransactionManagement 开启事务支持
@SpringBootApplication
@EnableTransactionManagement //SpringBoot开启事务的支持 这个注解可以不写,可有可无
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
springboot中pringmvc注解
常用注解
1.@Controller
Spring MVC的注解,处理http请求
2.@RestController
Spring4后新增注解,是@Controller注解功能的增强,是@Controller与@ResponseBody的组合注解;
如果一个Controller类添加了@RestController,那么该Controller类下的所有方法都相当于添加了@ResponseBody注解;
用于返回字符串或json数据。
3.@RequestMapping(常用)
支持Get请求,也支持Post请求
4.@GetMapping
RequestMapping和Get请求方法的组合只支持Get请求;Get请求主要用于查询操作。
5.@PostMapping
RequestMapping和Post请求方法的组合只支持Post请求;Post请求主要用户新增数据。
6.@PutMapping
RequestMapping和Put请求方法的组合只支持Put请求;Put通常用于修改数据。
7.@DeleteMapping
RequestMapping 和 Delete请求方法的组合只支持Delete请求;通常用于删除数据。
package com.ning.springboot.controller;
import com.ning.springboot.model.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
//@Controller
@RestController
/**
* @RestController: 相当于控制层类上加 @Controller + 方法上加 @ResponseBody
* 意味着当前控制层类中所有方法返回的都是JSON对象
*/
public class StudentController {
@RequestMapping(value = "/student")
// @ResponseBody
public Object stu(){
Student student = new Student();
student.setId(100);
student.setName("zhansan");
return student;
}
// 该方法支持 GET 和 POST 请求
@RequestMapping(value = "/queryStudentById",method = {RequestMethod.GET,RequestMethod.POST})
public Object queryStudentById(Integer id) {
Student student = new Student();
student.setId(id);
return student;
}
// 只支持 GET请求
// @RequestMapping(value = "/queryStudentById2",method = RequestMethod.GET)
@GetMapping("/queryStudentById2")
// 相当于上一句,只接收GET请求,如果请求方式不对,汇报405错误
// 该注解通过在查询数据的时候使用 ->查询
public Object queryStudentById2() {
return "ONLY GET METHOD";
}
// @RequestMapping(value = "/queryStudentById3",method = RequestMethod.POST)
@PostMapping("/queryStudentById3")
// 只接受POST请求
// 通常在新增数据的时候使用 ->新增
public Object queryStudentById3() {
return "POST METHOD";
}
// @RequestMapping(value = "/queryStudentById3",method = RequestMethod.DELETE)
@DeleteMapping("/queryStudentById4")
// 通常在删除数据的时候是使用 ->删除
public Object queryStudentById4() {
return "DELETE METHOD";
}
// @RequestMapping(value = "/queryStudentById5",method = RequestMethod.PUT)
@PutMapping("/queryStudentById5")
// 通常在修改数据的时候使用 ->更新
public Object queryStudentById5() {
return "UPDATE METHOD";
}
}
springboot 实现 RESTful
1、认识RESTful
REST(英文:Representational State Transfer,简称REST)
一种互联网软件架构设计的风格,但它并不是标准,它只是提出了一组客户端和服务器交互时的架构理念和设计原则,基于这种理念
和原则设计的接口可以更简洁,更有层次,REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。
任何的技术都可以实现这种理念,如果一个架构符合REST原则,就称它为RESTFul架构。
比如我们要访问一个http接口:http://localhost:8080/boot/order?id=1021&status=1
采用RESTFul风格则http地址为:http://localhost:8080/boot/order/1021/1
2、springboot开发RESTful
Spring boot开发RESTFul 主要是几个注解实现:
@PathVariable:获取url中的数据,该注解是实现RESTFul最主要的一个注解。
@GetMapping("/student/detail/{id}/{count}")
public Object Student3(@PathVariable("id") Integer id,
@PathVariable("count") Integer count){
Map<String,Object> resMap = new HashMap<>();
resMap.put("id",id);
resMap.put("count",count);
return resMap;
}
@PostMapping:接收和处理Post方式的请求
@DeleteMapping:接收delete方式的请求,可以使用GetMapping代替
@PutMapping:接收put方式的请求,可以用PostMapping代替
@GetMapping:接收get方式的请求
3、RESTful 优点
• 轻量,直接基于http,不再需要任何别的诸如消息协议,get/post/put/delete为CRUD操作
• 面向资源,一目了然,具有自解释性。
• 数据描述简单,一般以xml,json做数据交换。
• 无状态,在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度。
• 简单、低耦合
4、 测试
当两个RESTful访问路径冲突时,这个时候就会使用 不同注解来区分
@RequestMapping("/student/detail/{id}/{age}")
public Object Student1(@PathVariable("id") Integer id,
@PathVariable("age") Integer age){
Map<String,Object> resMap = new HashMap<>();
resMap.put("id",id);
resMap.put("age",age);
return resMap;
}
@RequestMapping("/student/detail/{id}/{count}")
public Object Student2(@PathVariable("id") Integer id,
@PathVariable("count") Integer count){
Map<String,Object> resMap = new HashMap<>();
resMap.put("id",id);
resMap.put("count",count);
return resMap;
}
当两个增加请求,使用的注解相同时,这个时候为了区分路径就会改变路径
@GetMapping(value = "/springBoot/order/{id}/{status}")
public Object queryOrder(@PathVariable("id") Integer id,
@PathVariable("status") Integer status) {
Map map = new HashMap();
map.put("id",id);
map.put("status",status);
return map;
}
@GetMapping(value = "/springBoot/{id}/order/{status}")
public Object queryOrder1(@PathVariable("id") Integer id,
@PathVariable("status") Integer status) {
Map map = new HashMap();
map.put("id",id);
map.put("status",status);
return map;
}
springboot 集成 redis
步骤
1、在pom.xml文件中添加依赖
<!-- springboot 集成 redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置主配置文件
# 配置redis 信息
spring.redis.host=192.168.144.128
spring.redis.port=6379
3、service接口以及实现类
/***********************************************************************************/
package com.ning.springboot.service;
public interface StudentService {
/**
* 将值存放到 redis 中
* @param key
* @param value
*/
void put(String key, String value);
String get(String key);
}
/***********************************************************************************/
接口实现类
package com.ning.springboot.service.impl;
import com.ning.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 {
@Autowired
private RedisTemplate<Object,Object> redisTemplate; // 泛型里面两个都是Object
@Override
public void put(String key, String value) {
redisTemplate.opsForValue().set(key,value); // opsForValue() 表示String类型
}
@Override
public String get(String key) {
String count = (String) redisTemplate.opsForValue().get(key);
return count;
}
}
4、controller层
package com.ning.springboot.controller;
import com.ning.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("/student")
@ResponseBody
public Object put(String key, String value){
studentService.put(key,value);
return "值已添加到redis";
}
@RequestMapping("/toget")
@ResponseBody
public String get(){
String count = studentService.get("1001");
return "数据库中的值为:"+count;
}
}
springboot集成Dubbo分布式框架
前提要开启zookeeper
接口工程:存放实体类bean和业务接口
服务提供者:业务接口的实现类并将服务暴露且注册到注册中心,调用数据持久层
--添加依赖(dubbo,注册中心,接口工程)
--配置服务提供者核心配置文件
服务消费者:处理浏览器客户端发送的请求,从注册中心调用服务提供者所提供的服务
--添加依赖(dubbo,注册中心,接口工程)
--配置服务消费者核心配置文件
程序主入口
package com.ning.springboot;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // 开启spring注解配置
@EnableDubboConfiguration // 开启dubbo配置
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1、创建一个接口工程 接口工程中存放的是 service 接口
package com.ning.springboot.service;
/**
* @author XUN~MLF
*/
public interface StudentService {
/**
* 获取学生总人数
* @return
*/
Integer queryAllStudentCount();
}
2、创建服务提供者
2.1 配置 pom.xml 文件 添加依赖
<!--Dubbo集成springboot依赖-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--ZooKeeper注册中心依赖-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!--Dubbo接口工程依赖-->
<dependency>
<groupId>org.example</groupId>
<artifactId>010-springboot-dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
2.2 在主配置文件中配置 dubbo
# 设置端口号
server.port=8081
# 设置上下文根
server.servlet.context-path=/
# dubbo配置
spring.application.name=011-springboot-dubbo-provider
# 当前工程是一个服务提供者
spring.dubbo.server=true
# 设置注册中心
spring.dubbo.registry=zookeeper://localhost:2181
2.3 接口的实现类
package com.ning.springboot.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.ning.springboot.service.StudentService;
import org.springframework.stereotype.Component;
/**
* @author XUN~MLF
*/
@Component
@Service(interfaceClass = StudentService.class,version = "1.0.0",timeout = 15000)
public class StudentServiceImpl implements StudentService {
@Override
public Integer queryAllStudentCount() {
// 调用持久层
return 1250;
}
}
3、创建服务消费者
3.1 配置 pom.xml 文件 添加依赖
<!--Dubbo集成springboot依赖-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--ZooKeeper注册中心依赖-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!--Dubbo接口工程依赖-->
<dependency>
<groupId>org.example</groupId>
<artifactId>010-springboot-dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
3.2 在主配置文件中配置 dubbo
# 设置端口号
server.port=8082
# 设置上下文根
server.servlet.context-path=/
# dubbo配置
spring.application.name=012-springboot-dubbo-consumer
# 设置注册中心
spring.dubbo.registry=zookeeper://localhost:2181
3.3 编写 controller 层
package com.ning.springboot.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.ning.springboot.service.StudentService;
import org.springframework.stereotype.Controller;
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/count")
@ResponseBody
public Object studentCount(){
Integer allStudentCount = studentService.queryAllStudentCount();
return "学生总人数:"+allStudentCount;
}
}
其中出现的注解 :
@EnableDubboConfiguration // 开启dubbo配置 在主程序入口添加
@Component
@Service(interfaceClass = StudentService.class,version = “1.0.0”,timeout = 15000) 这两个注解在服务提供者的接口实现类中添加
@Reference(interfaceClass = StudentService.class,version = “1.0.0”, check = false) 在controller 中导入接口实现类的时候添加
SpringBoot集成以上所学
接口工程:存放实体类bean和业务接口
服务提供者: 它是一个SpringBoot框架web项目,集成MyBatis ,Redis
--添加依赖:MyBatis依赖,MySQL驱动依赖,Dubbo依赖,zookeeeper依赖,Redis依赖,接口工程
--配置springboot核心配置文件
—配置连接数据库
--配置连接redis
– 配置连接 dubbo
服务消费者:它是它是一一个SpringBoot框架web项目,集成JSP , dubbo
-添加依赖:Dubbo依赖,zookeeper依赖,解析JSP页面的依赖,接口工程
配置SpringBoot核心配置文件
--配置视图解析器
—配置dubbo
接口工程 存放实体类和接口
服务提供者 存放接口实现类和 dao 接口以及接口实现类
<!--Mybatis集成springboot依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--MySQL的驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- springboot 集成 redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Dubbo集成springboot依赖-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--ZooKeeper注册中心依赖-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!--Dubbo接口工程依赖-->
<dependency>
<groupId>org.example</groupId>
<artifactId>013-springboot-all-interface</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!--在build标签中 手动指定文件解析 dao接口映射文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<!--添加mysql反向工程依赖-->
<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>
# 主配置文件
###################################################################################################
# 设置端口号
server.port=8081
# 设置上下文根
server.servlet.context-path=/
# 设置连接数据库信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
# 设置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
# 设置dubbo
spring.application.name=014-springboot-all-provider
# 声明当前工程为服务提供者
spring.dubbo.server=true
# 设置注册中心
spring.dubbo.registry=zookeeper://localhost:2181
接口实现类
package com.ning.springboot.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.ning.springboot.mapper.StudentMapper;
import com.ning.springboot.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
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;
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
@Override
public Student queryStudentById(Integer id) {
return studentMapper.selectByPrimaryKey(id);
}
@Override
public Integer queryAllStudentCount() {
// 首先去redis缓存中查询,如果有就直接使用,如果没有就去数据库查寻,并放到redis缓存中
// 提升系统性能,提升用户体验
Integer allStudentCount = (Integer) redisTemplate.opsForValue().get("allStudentCount");
// 判断是否有值
if( allStudentCount == null){
// 去数据库查询
allStudentCount = studentMapper.seleceAllStudentCount();
// 并存放到redis缓存中
redisTemplate.opsForValue().set("allStudentCount",allStudentCount,30, TimeUnit.SECONDS);
}
return allStudentCount;
}
}
服务消费者 controller层
pom.xml文件和提供者一样
<!--Dubbo集成springboot依赖-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--ZooKeeper注册中心依赖-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!--Dubbo接口工程依赖-->
<dependency>
<groupId>org.example</groupId>
<artifactId>013-springboot-all-interface</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!--如果只是使用JSP页面,可以只添加该依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<!--源文件位置-->
<directory>src/main/webapp</directory>
<!--指定编译到META-INF/resource,该目录不能随便写-->
<targetPath>META-INF/resources</targetPath>
<!--指定要把哪些文件编译进去,**表示webapp目录及子目录,*.*表示所有文件-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
主配置文件
# 设置端口号
server.port=8080
# 设置上下文根
server.servlet.context-path=/
# 设置dubbo
spring.application.name=015-springboot-all-consumer
# 设置注册中心
spring.dubbo.registry=zookeeper://localhost:2181
# 配置视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
controller
package com.ning.springboot.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.ning.springboot.model.Student;
import com.ning.springboot.service.StudentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
@Reference(interfaceClass = StudentService.class,version = "1.0.0" ,check =false)
private StudentService studentService;
@RequestMapping("/student/detail/{id}")
public Object studentDetail(@PathVariable("id") Integer id){
Student student = studentService.queryStudentById(id);
return student;
}
@GetMapping("/student/count")
public Object allStudentCount(){
Integer allStudentCount = studentService.queryAllStudentCount();
return "学生的总人数:"+allStudentCount;
}
}
springboot 中使用拦截器
步骤
1、先定义一个拦截器类 实现 HandlerInterceptor 这个接口 并重写3个方法
package com.ning.springboot.interceptor;
import com.ning.springboot.model.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("进入拦截器----------");
// 编写业务拦截的规则
// 从session中获取用户信息
User user = (User) request.getSession().getAttribute("user");
//判断是否登录
if (user == null) {
// 未登录
response.sendRedirect(request.getContextPath() + "/user/error");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2、创建拦截器配置类 添加注解@Configuration
package com.ning.springboot.config;
import com.ning.springboot.interceptor.UserInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration // 定义此类配置类 相当一之前的web.xml配置文件
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 要拦截user 下的所有请求,必须要用户登录才能访问
// 一些不需要登录就能访问的 路径也被拦截了
String[] addPathPatterns = {
"/user/**"
};
// 排除一些不需要登录就能访问的路径
String[] excludePathPatterns = {
"/user/login","/user/error","/user/out"
};
registry.addInterceptor(new UserInterceptor()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
}
}
3、实体类
package com.ning.springboot.model;
public class User {
private Integer id;
private String username;
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;
}
}
4、controller 层
package com.ning.springboot.controller;
import com.ning.springboot.model.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/user")
public class UserController {
// 用户登录请求
@RequestMapping("/login")
public Object login(HttpServletRequest request){
// 将用户的信息存放到session中
User user = new User();
user.setId(1001);
user.setUsername("lisi");
request.getSession().setAttribute("user",user);
return "Login seccess";
}
// 该请求需要用户登录之后才能访问
@RequestMapping("/center")
public Object center(){
return "see center message";
}
// 该请求用户登录也能访问
@RequestMapping("/out")
public Object out(){
return "out";
}
// 如果用户没有登录访问了需要登录才能访问的页面,之后会跳转到该路径
@RequestMapping("/error")
public Object error(){
return "error";
}
}
springboot中使用过滤器的两种方式
1、添加注解法
@ServletComponentScan(basePackages = “com.ning.sprinboot.filter”) 在主程序入口加
@WebFilter(urlPatterns = “/myfilter”) 在过滤器类中加
package com.ning.sprinboot.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/myfilter")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("--------------已经进入过滤器01---------------");
filterChain.doFilter(servletRequest, servletResponse);
}
}
/*****************************************************************************************************/
package com.ning.sprinboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan(basePackages = "com.ning.sprinboot.filter")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2、注册组件
新建一个文件
@Configuration // 定义此类为配置类
@Bean 配置
package com.ning.springboot.config;
import com.ning.springboot.filter.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.FilterRegistration;
@Configuration // 定义此类为配置类
public class MyConfig {
@Bean
public FilterRegistrationBean myFilterRegistrationBean(){
// 注册过滤器
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
// 添加过滤路径
filterRegistrationBean.addUrlPatterns("/user/*"); // 这里路径 是/* 不能是 /**
return filterRegistrationBean;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--日志的级别:
trace < debug < info < warn < error < fatal
-->
<configuration scan="true" scanPeriod="10 seconds">
<!--输出到控制台-->
<appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<appender name="file"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>D:/log/springboot-logback.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>D:/log/springboot-logback.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory> <!--日志保留30天-->
</rollingPolicy>
</appender>
<!-- logback:包路径 -->
<logger name="com.ning.springboot.mapper" level="DEBUG" />
<!--日志输出-->
<root level="info">
<appender-ref ref="console"/>
<!-- <appender-ref ref="file"/>-->
</root>
</configuration>
springboot 集成 thymeleaf
1、添加依赖
<!--集成thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2、缓存设置
# 设置thymeleaf模板引擎的缓存,默认为true ,我们要关闭
spring.thymeleaf.cache=false
# 然后在tomcat的配置中,改为 update resources
3、在html标签中添加 xmlns:th=“http://www.thymeleaf.org”
变量表达式
选择变量表达式 (不推荐)
<h2>选择变量表达:又叫做*号表达式</h2>
<h3 style="color: red">用户对象仅在div范围内有效</h3>
<div th:object="${user}">
<span th:text="*{id}"></span><br/>
<span th:text="*{nick}"></span><br/>
<span th:text="*{phone}"></span><br/>
<span th:text="*{address}"></span><br/>
</div>
标准变量表达式
<h2>标准变量表达:又叫做*号表达式</h2>
<span th:text="${user.id}"></span><br/>
<span th:text="${user.nick}"></span><br/>
<span th:text="${user.phone}"></span><br/>
<span th:text="${user.address}"></span><br/>
url表达式
1.语法@{…}
2.说明主要用于链接、地址的展示
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>路径表达式</title>
</head>
<body>
<h1>url路径表达式 @{}</h1>
<h1>绝对路径写法</h1>
<a href="http://www.baidu.com">跳转到百度</a><br>
<a href="/message">跳转到百度</a><br>
<a th:href="@{http://localhost:8080/message}">绝对路径跳转到/message</a><br>
<h1>相对路径</h1>
<a th:href="@{/message}">跳转到/message</a><br>
<h1>相对路径带参数</h1>
<a th:href="@{/text?username=lisi}">相对路径带参数</a>
<h1>相对路径带参数(后台传值)</h1>
<a th:href="@{'/text?username='+${id}}">后台获取数据</a>
<h1>带多个参数的表达式</h1>
<a th:href="@{'/text?id='+${id}+'&username='+${username}+'&age='+${age}}">后台获取多个数值</a><br>
<a th:href="@{/text(id=${id},username=${username},age=${age})}">获取多个参数</a>
<a th:href="@{'/text2/'+${id}}">restful风格</a>
</body>
</html>
lombok插件的使用
1、加入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
2、idea下载插件
3、常用注解
@Data:注解在类上,将类提供的所有属性都添加get、set方法,并添加、equals、canEquals、hashCode、toString方法
@Setter:注解在类上,为所有属性添加set方法、注解在属性上为该属性提供set方法
@Getter:注解在类上,为所有的属性添加get方法、注解在属性上为该属性提供get方法
@NoArgsConstructor:创建一个无参构造函数
@AllArgsConstructor:创建一个全参构造函数, 替代@Autowired构造注入,多个bean 注入时更加清晰
@ToString:创建一个toString方法
@NotNull:在参数中使用时,如果调用时传了null值,就会抛出空指针异常
@Synchronized 用于方法,可以锁定指定的对象,如果不指定,则默认创建一个对象锁定
@Log作用于类,创建一个log属性
@Builder:使用builder模式创建对象
@Accessors(chain = true)使用链式设置属性,set方法返回的是this对象。
@RequiredArgsConstructor:创建对象, 例: 在class上添加
@RequiredArgsConstructor(staticName = “of”)会创建生成一个静态方法
@UtilityClass:工具类再也不用定义static的方法了,直接就可以Class.Method 使用
@ExtensionMethod:设置父类
@FieldDefaults:设置属性的使用范围,如private、public等,也可以设置属性是否被final修饰
@EqualsAndHashCode:重写equals和hashcode方法。
@Cleanup: 清理流对象,不用手动去关闭流
springboot热部署插件
<!--SpringBoot热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
遍历集合
<h1>th:each遍历List集合</h1>
<!--
user: 当前循环对象的变量名称(随意)
userStat: 当前循环对象状态的变量(可忽略不写,默认就是对象变量名+Stat)
${userList}: 当前循环的集合
-->
<div th:each="user,userStat:${userList}">
<span th:text="${userStat.index}"></span>
<span th:text="${user.id}"></span>
<span th:text="${user.phone}"></span>
<span th:text="${user.name}"></span>
<span th:text="${user.address}"></span><br/>
</div>
<h1>th:each遍历Map集合</h1>
<div th:each="map:${userMap}">
<span th:text="${map.key}"></span>
<span th:text="${map.value}"></span>
<span th:text="${map.value.id}"></span>
<span th:text="${map.value.phone}"></span>
<span th:text="${map.value.nick}"></span>
<span th:text="${map.value.address}"></span>
</div>
条件判断
<div style="color: red">th:unless是th:if的一个相反操作 </div>
<span th:unless="${sex == 1}">
男
</span>
<span th:unless="${sex == 2}">
女
</span>
<hr>
<div style="color: red">switch,case判断语句</div>
<div th:switch="${sex}">
<p th:case="1">性别:男</p>
<p th:case="2">性别:女</p>
<p th:case="*">性别:未知</p>
</div>
内敛表达式
<h1>一般写法</h1>
<div th:text="${data}"></div>
<hr>
<h1>内敛文本 th:inline="text"</h1>
<div th:inline="text">
数据:[[${data}]]
</div>
<hr>
<h1>内敛脚本 th:inline="javascript"</h1>
<!--不添加th:inline="javascript" 数据无法显示-->
<script type="text/javascript" th:inline="javascript">
function show() {
alert([[${data}]])
alert("----------");
}
</script>
<button th:onclick="show()">展示数据</button>
字面量
<h3>文本字面量</h3>
<span th:href="@{'/literal?sex='+${sex}}"></span>
<span th:text="hello"></span>
<h3>数字字面量</h3>
<p>今年是<span th:text="2017">1949</span>年</p>
<p>20年后, 将是<span th:text="2017 + 20">1969</span>年</p>
<h3>boolean字面量</h3>
<div th:if="${flog}">
执行成功
</div>
运算符
<!--
算术运算:+ , - , * , / , %
关系比较: > , < , >= , <= ( gt , lt , ge , le )
相等判断:== , != ( eq , ne )
-->
<div th:text="${sex eq 1 ? '男' : '女'}"></div>
<h2>算数运算</h2>
20+5=<span th:text="20+5"></span><br>
20-5=<span th:text="20-5"></span><br>
20*5=<span th:text="20*5"></span><br>
20/5=<span th:text="20/5"></span><br>
20%5=<span th:text="20%5"></span><br>
字符串拼接
<body>
<span>共120条12页,当前第1页,首页,上一页 下一页 尾页</span>
<h2>优雅的拼接: |要拼接的字符串| </h2>
<span th:text="|共${totalRows}条${totalPage}页,当前第${currentPage}页,首页,上一页 下一页 尾页|">共120条12页,当前第1页,首页,上一页 下一页 尾页</span>
</body>
功能表达式对象
request.getSession().setAttribute("data","sessionData");
<h2>从session中获取值</h2>
<span th:text="${#session.getAttribute('data')}"></span><br>
<span th:text="${#httpSession.getAttribute('data')}"></span><br>
<span th:text="${session.data}"></span><br>
<script type="text/javascript" th:inline="javascript">
// 获取协议名称
var schema = [[${#request.getScheme()}]];
// 获取服务器名称
var serverName = [[${#request.getServerName()}]];
// 获取端口号
var serverPort = [[${#request.getServerPort()}]];
// 获取上下文根
var contextPath = [[${#request.getContextPath}]];
var allPath = schema + "://"+serverName+":"+serverPort+contextPath;
var requestURL = [[${#httpServletRequest.requestURL}]];
alert(allPath);
alert(requestURL);
</script>
model.addAttribute("time",new Date());
model.addAttribute("data","springboothelloword");
<body>
<div th:text="${time}"></div>
<div th:text="${#dates.format(time,'yyyy-MM-dd HH-mm-ss')}"></div>
<div th:text="${data}"></div>
<div th:text="${#strings.substring(data,0,10)}"></div>
</body>
springboot集成swagger
1、简单测试
1、创建一个springboot项目
2、加入依赖
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
3、编写一个简单的controller
@RestController
public class UserController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
4、配置swagger ==》config
@Configuration
@EnableSwagger2 // 开启swagger2
public class SwaggerConfig {
}
5、测试运行
2、配置swagger
Swagger的bean实例Docket
@Configuration
@EnableSwagger2 // 开启swagger2
public class SwaggerConfig {
/**
* 配置swagger的docket的bean实例
* @return
*/
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
/**
* 配置swagger信息 apiInfo
*/
private ApiInfo apiInfo(){
// 作者信息
Contact contact = new Contact("XUM~MLF", "http://www.baidu.com", "2407942305@qq.com");
return new ApiInfo(
"狂神日记",
"扬帆远航",
"v1.0",
"http://www.baidu.com",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
swagger配置扫描路径
Docket.select()
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// enable():是否启用swagger
.enable(false)
.select()
// RequestHandlerSelectors,配置扫描接口的方式
// basePackage : 指定要扫描的包
// any() :扫描全部
// none():都不扫描
// withClassAnnotation(): 扫描类上的注解
// withMethodAnnotation():扫描方法上的注解
.apis(RequestHandlerSelectors.basePackage("com.ning.springboot.controller"))
// paths(): 过滤什么路径
// .paths(PathSelectors.ant("/ning/**")
.build();
}
我们只希望在生产环境下使用swagger,在发布的时候不使用?
- 判断是不是生产环境 flag = false
- 注入enable(flag)
@Bean
public Docket docket(Environment environment){
/**
* 获取项目的环境
* */
// 设置要显示的swagger环境
Profiles profiles = Profiles.of("dev");
// environment.acceptsProfiles,判断是否处在自己设定的环境当中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// enable():是否启用swagger ,如果为false,则swagger不能在浏览器中访问
.enable(flag)
.select()
// RequestHandlerSelectors,配置扫描接口的方式
// basePackage : 指定要扫描的包
// any() :扫描全部
// none():都不扫描
// withClassAnnotation(): 扫描类上的注解
// withMethodAnnotation():扫描方法上的注解
.apis(RequestHandlerSelectors.basePackage("com.ning.springboot.controller"))
// paths(): 过滤什么路径
// .paths(PathSelectors.ant("/ning/**")
.build();
}
实体类配置
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
public String username;
@ApiModelProperty("密码")
public String password;
}
security
加入依赖之后就可以使用security
<!--spring security 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
设置登陆的用户名和密码
1、通过配置文件
# 通过配置文件设置security 的用户名和密码
spring.security.user.name=user
spring.security.user.password=123
2、通过配置类
/**
* 通过配置类设置账号密码
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); // 密码加密
String password = passwordEncoder.encode("123");
auth.inMemoryAuthentication().withUser("tom").password(password).roles("user");
}
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
}
3、自定义编写实现类
自定义是实现类:
@Service("userDetailsService")
public class UserSercive implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User("mike",new BCryptPasswordEncoder().encode("123"),auths);
}
}
配置类:
@Configuration
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
}
查询数据库实现用户登录
1、加入依赖
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--MySQL的驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2、创建实体类
3、整合mybatis-plus ,创建接口。集成mp接口
@Repository
public interface UserMapper extends BaseMapper<User> {
}
4、创建自定义配置类以及service实现查询数据库认证
配置类:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
}
@Service("userDetailsService")
public class UserService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 调用userMapper方法,跟据用户名查询数据库
QueryWrapper<User> wrapper = new QueryWrapper<>();
// where username=?
wrapper.eq("username",username);
User users = userMapper.selectOne(wrapper);
if (users == null){
throw new UsernameNotFoundException("用户不存在");
}
List<GrantedAuthority> auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new org.springframework.security.core.userdetails.User(users.getUsername(),
new BCryptPasswordEncoder().encode(users.getPassword()),auths);
}
}
5、在启动类添加@MapperScan("com.ning.springboot.mapper")
6、在配置文件中配置连接数据库的信息
#配置数据库的连接信息
#注意这里的驱动类有变化
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
自定义登录页面
在配置类中添加
@Override
protected void configure(HttpSecurity http) throws Exception{
http.formLogin() // 自定义自己的登录页面
.loginPage("/login.html") // 登录页面设置
.loginProcessingUrl("/user/login") // 登录访问路径
.defaultSuccessUrl("/test/index").permitAll() // 登录成功后,跳转路径
.and().authorizeRequests().antMatchers("/","/user/login","/test/hello").permitAll()
.anyRequest().authenticated()
.and().csrf().disable(); // 关闭crsf防护
}
静态页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="username"/><br>
密码:<input type="text" name="password"/><br>
<input type="submit" value="login"/>
</form>
</body>
</html>
controller:
@RestController
@RequestMapping("/test")
public class UserController {
@GetMapping("/hello")
public String hello(){
return "hello security";
}
@GetMapping("index")
public String index(){
return "hello index";
}
}
基于权限进行访问控制
第一个方法:hasAuthority 方法 :针对某一个权限
实现步骤:
1、在配置类设置当前访问地址有哪些权限
.antMatchers("/index").hasAuthority("admin")
2、在UserService中把返回User对象设置权限
List<GrantedAuthority> auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
第二个方法:针对多个权限
.antMatchers("/index").hasAnyAuthority("root,user")
第三种方法:hasRole
.antMatchers("/index").hasRole("sale")
ist<GrantedAuthority> auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("root,ROLE_sale"); // 要加前缀ROLE_ 否则无法访问
第四种方法:hasAnyRole
.antMatchers("/index").hasAnyRole("sale,root")
自定义无权访问跳转页面
// 配置没有权限访问跳转自定义页面
http.exceptionHandling().accessDeniedPage("/error.html");
认证授权使用注解
第一个注解:@Secured
1、在主程序类种添加开启注解
@EnableGlobalMethodSecurity(securedEnabled = true) // 开启security权限认证注解
2、在controller方法上使用注解,设置角色
@GetMapping("/root")
@Secured({"ROLE_root"})
public String root(){
return "hello root";
}
3、在UserService中设置
List<GrantedAuthority> auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_sale");
第二个注解:**@PreAuthorize ** 在方法执行执行做校验
在主程序中
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) // prePostEnabled = true
@GetMapping("/root")
@PreAuthorize("hasAnyAuthority('root')")
public String root(){
return "hello root";
}
第三个方法:@PostAuthorize :在方法执行之后做校验
退出登录:
// 退出
http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();
实现记住我功能
配置类中设置:
// 记住我
http.rememberMe();
<input type="checkbox" name="remember-me"/>记住我<br> <!--name值属性必须是 name="remember-me" -->
shiro
2021/05/09 XUN~MLF