Spring家族介绍与开发环境
课程主要内容
-
Spring能做什么?
-
Spring开发环境搭建
-
HelloWorld程序
Spring能做什么?
Spring是一个轻量级的控制反转(IoC/di)和面向切面编程(AOP) 的对象容器框架
Spring官网:http://spring.io/
Spring 是一个于 2003 年兴起的一个轻量级的 Java 开源开发框架
如今Spring已是Java项目的标配,它极大的简化了开发过程,降低了开发难度。
-
方便解耦,简化开发;
-
AOP 编程的支持;
-
声明式事务的支持;
-
方便程序的测试;
-
方便集成各种优秀框架。
IoC
Inversion of Control
AOP
Aspect Oriented Programming
Spring5新特性
Spring5 是一个重要的版本,距离SpringFramework4差不多四年
-
支持JDK8
-
Spring 接口中的默认方法
-
基于 Java8 反射增强的内部代码改进
-
在框架代码中使用函数式编程 - lambda表达式 和 stream流
-
-
响应式编程支持Spring Web Reactive异步的、非阻塞的、事件驱动的服务
-
支持J2EE7
-
Servlet 3.1
-
JMS 2.0
-
JPA 2.1
-
JAX-RS 2.0
-
-
Bean Validation 1.1
-
Hibernate 5
-
Jackson 2.6
-
EhCache 2.10
-
JUnit 5
-
Tiles 3
-
Kotlin
开发环境
Spring Jar包
SpringFramework官网下载地址:
https://repo.spring.io/libs-release-local/org/springframework/spring/
解压缩Jar包可以看见如下结构
-
Doc 文档
-
Libs Jar包
-
Schema XML约束
-
license.txt 许可协议
-
notice.txt 注意事项
-
readme.txt 读我
常用Jar包
spring-core | 框架的基础功能,包括IOC和AOP功能 |
---|---|
spring-aspects | 提供了与AspectJ的集成,AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。 |
spring-beans | 所有应用都要用到,包含访问配置文件、创建和管理 bean 以及进行 Inversion of Control(控制反转) / Dependency Injection(依赖注入)操作相关的所有类。外部依赖 spring-core |
spring-context | |
spring-aop、spring-instrument | 面向切面编程、植入代理 |
spring-expression | 模块提供了强大的表达式语言去支持查询和操作运行时对象图。这是对JSP 2.1规范中规定的统一表达式语言的扩展。该语言支持设置和获取属性值,属性分配,方法调用,访问数组,集合和索引器的内容,逻辑和算术运算,变量命名以及从Spring的IoC容器中以名称检索对象。 它还支持列表投影和选择以及常见的列表聚合。 |
spring-messaging | 消息传递 |
spring-jdbc、spring-jms、spring-orm | 数据访问支持 |
spring-jcl | Jakarta Commons Logging采用了设计模式中的“适配器模式”,它对外提供统一的接口,然后在适配类中将对日志的操作委托给具体的日志框架。 |
spring-tx | 事务 |
spring-webmvc、spring-web | Webmvc框架支持 |
spring-webflux | Servlet3.1 + Netty 方式的WebMvc |
spring-websocket | 对ws支持 |
commons-logging
运行Spring程序额外还需要commons-logging包
http://commons.apache.org/proper/commons-logging/download_logging.cgi
开发工具
可以使用Eclipse、Idea等
推荐使用官方开发工具STS
环境变量
window下配置
-
新建->变量名"JAVA_HOME",变量值"C:\Java\jdk1.8.0_05"(即JDK的安装路径)
-
编辑->变量名"Path",在原变量值的最后面加上“;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin”
-
新建->变量名“CLASSPATH”,变量值“.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar”
在控制台分别输入java,javac,java -version 命令,测试环境是否设置成功
Hello world
新建java项目
包引入
配置文件
在src下新建
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
"src/applicationContext.xml"
<bean id="user" class="com.msb.User"></bean>
</beans>
Bean
建立准备由Spring管理的Bean
包含两个属性,生成get/set方法
private String name;
private Integer age;
测试类
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User)ctx.getBean("user");
user.setName("uu");
user.setAge(18);
System.out.println(ToStringBuilder.reflectionToString(user));;
ToStringBuilder 工具类
-
Commons项目中用来处理Java基本对象方法的工具类包,可以简化很多平时经常要用到的写法,例如判断字符串是否为空等等。
-
是一个最常用的工具,作为jdk的补充。
-
Lang下有很多Utils类,提供了若干static方法供调用,涵盖了字符串操作、字符操作、JVM交互操作、归类、异常和位域校验等等。
项目地址
http://commons.apache.org/proper/commons-lang/download_lang.cgi
Spring是一个对象管理容器,自动化完成了创建、初始化、销毁等工作。
传统的方式
Person person = new Person();
person.setAge(18);
person.setName("zhangsan");
IoC概念
IoC是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式之一是DI。
基于XML的DI
ApplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
XML文件结构
- <beans beans是xml文件的根节点
- xmlns=http://www.springframework.org/schema/beans xmlns=xml NameSpace 类似于java中的package
- xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi是指xml文件遵守xml规范,xsi全名:xml schema instance
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 是指具体用到的schema资源
真的去网上找xsd文件?
当然不是
spring在加载xsd文件时总是先试图在本地查找xsd文件(spring的jar包中已经包含了所有版本的xsd文件),如果没有找到,才会转向去URL指定的路径下载
验证PluggableSchemaResolver.class中
=后面是包名以及具体xsd文件位置
多配置文件
ApplicationContext加载多文件
new ClassPathXmlApplicationContext("applicationContext.xml","application-service.xml");
引入外部文件
<import resource="application-service.xml"/>
Bean的定义与注册
Spring的配置文件是用于指导Spring工厂进行Bean的生产、依赖关系注入及Bean实例分发的“图纸”,它是一个或多个标准的XML文档
<bean id="food" class="com.msb.Food"></bean>
一个bean只能有一个id,但是可以有多个name作为别名
Alias 别名
<alias name="user" alias="my_user_bean" />
spring ioc container
spring ioc container 管理一个或多个bean,bean来自xml中对bean定义的元数据(configuration metadata)
元数据信息
Class | 类 |
Name,id | 标识 |
Scope | 作用域 |
Constructor arguments | 构造器注入 |
Properties | 属性注入 |
autowiring mode | 自动装配 |
lazy-initialization mode | 懒加载 |
initialization method | 初始化 |
destruction method | 销毁 |
构造器注入 constructor-arg
Person的构造器
public Person(String name, Integer age, Food food) {
super();
this.name = name;
this.age = age;
this.food = food;
}
Xml
指定name
<bean id="person" class="com.msb.Person">
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="name" value="zhangsan"></constructor-arg>
</bean>
指定类型
<constructor-arg type="int" value="7500000"/>
指定index
<constructor-arg index="0" value="7500000"/>
属性注入
<bean id="person" class="com.msb.Person">
<property name="age" value="19"></property>
<property name="name" value="zhangsan"></property>
</bean>
使用p-namespace
属性注入
添加一个namespace
xmlns:p=http://www.springframework.org/schema/p
使用 p
<bean id="person" class="com.msb.Person" p:age="21" p:name = "zhangsan">
<bean id="person" class="com.msb.Person" p:age="21" p:name = "zhangsan" p:food-ref="food">
使用c- namespace
构造器注入
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email= "foo@bar.com"/>
使用java.util.Properties
在set方法中把properties
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
this.name=properties.getProperty("name");
}
对其他Bean的引用
<property name="food" ref="food"></property>
<bean id="food" class="com.msb.Food"></bean>
集合
Array
private String[] myArray;
<property name="myArray">
<array>
<value>北京</value>
<value>上海</value>
</array>
</property>
Properties
private Properties adminEmails;
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
List
private List someList;
<property name="someList">
<list>
<value>apple</value>
<value>orange</value>
</list>
</property>
Map
private Map someMap;
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="food"/>
</map>
</property>
depends-on 提前初始化
可以使某个bean在创建前,先创建别的bean
lazy-init
在容器启动后,bean被使用到的时候才加载。可以使用的lazy-init属性
bean id="person" class="com.msb.Person" lazy-init="false"
作用域
spring为bean提供了6种作用域,其中4种只有在web-aware的ApplicationContext种才有用。用户也可以创建自定义的作用域。
singleton 、prototype 、websocket、request、session、application
singleton scope 单例作用域
每一个类,在一个容器内只能产生一个实例
prototype scope 原型作用域
该bean每次被注入,或者使用getBean()方法获取时,都返回一个新的实例。
Request scope
该作用域的bean,在每个HTTP request都会新建一个实例,当一个request结束后,该实例也会被丢弃。
Session scope
某一个用户在一段时间内,会使用同一个session,session有超时时间,过了超时时间则session失效。不同用户使用不同的session。
Application scope
该作用域的bean,每一个application会创建一个
MVC下Spring的单例
想在一个singleton内多次调用短存活时间的bean(propotype、request、session等),希望调用的是不同的实例,那么就需要使用AOP proxy技术
线程安全问题
业务对象并没有做线程的并发限制,因此不会出现各个线程之间的等待问题,或是死锁问题
MVC中的实体bean不是单例的
成员变量
在并发访问的时候这些成员变量将会是并发线程中的共享对象,也是影响线程安全的重要因素
引用类型的成员
其中引用类型的成员变量即我们在controller中注入的service,在service中注入的dao,这里将其定义为成员变量主
要是为了实例化进而调用里面的业务方法,在这些类中一般不会有全局变量,因此只要我们的业务方法不含有独立的
全局变量即使是被多线程共享,也是线程安全的。
Controller service dao 层中的业务类是多线程共享的,但是每个线程在处理数据的时候具体处理的数据是在每个线程中各自有一份。
controller层
- final类型 线程安全
- 成员变量 有状态数据有线程安全问题
循环依赖的bean
构造器注入循环依赖
创建3个类
循环引用属性
A类中 -> B类的一引用 -
当循环依赖的bean都是通过构造器注入依赖的时候,无论这些bean是singleton还是prototype,在获取bean的时候都会失败。
通过属性注入
- 循环依赖的bean都是singleton 成功
- 循环依赖的bean都是prototype 失败
- 同时有singleton和prototype 当先获取的那个bean是singleton时,就会成功,否则失败
当Spring容器在创建A时,会发现其引用了B,从而会先去创建B。同样的,创建B时,会先去创建C,而创建C时,又先去创建A。最后A、B、C之间互相等待,谁都没法创建成功
IoC与动态代理
Maven方式创建Spring工程
工程创建
1.新建项目 选择Maven Project
2.勾选 Create a simple project
3.添加项目信息
-
Group id :包名
-
Artifact id:标识名
-
Name:项目名
依赖引入
Maven 中央仓库
使用国内镜像
创建一个maven的配置文件
参照:
http://maven.apache.org/settings.html
Pom.xml
```xml
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
```
空值注入
Value标签
标识空值 或空字符串 “”
<property name="name"><value></value></property>
Null标签
标识Null
<property name="name"><null></null></property>
工厂方式注入
为满足更复杂的需求,Spring也提供了工厂方式来创建更加灵活的Bean。
留意观察工厂类和实现类的创建次数
动态工厂
抽象接口 Car
public interface Car {
public String getName();
public String getPrice();
}
实现类 BMW车
public class Bmw implements Car{
public String getName() {
// TODO Auto-generated method stub
return "别摸我";
}
public String getPrice() {
// TODO Auto-generated method stub
return "500000RMB";
}
}
汽车工厂类 CarFactory
public class CarFactory {
public Car getCar(String name) throws Exception{
if (name.endsWith("bmw")) {
return new Bmw();
}else {
throw new Exception("car not fond");
}
}
}
Bean配置
<bean id="carFactory" class="com.msb.CarFactory"></bean>
<bean id="car" factory-bean="carFactory" factory-method="getCar" >
<constructor-arg value="bmw"></constructor-arg>
</bean>
静态工厂
Bean配置
<bean id="carStatic" class="com.msb.CarFactoryStatic" factory-method="getCar">
<constructor-arg value="bmw"></constructor-arg>
</bean>
工厂类
public class CarFactoryStatic {
public static Car getCar(String name) throws Exception{
if (name.endsWith("bmw")) {
return new Bmw();
}else {
throw new Exception("car not fond");
}
}
}
autowire自动注入
使用自动需要在配置文件中bean上添加autowire
<bean id="person" class="com.msb.Person" autowire="byName">
</bean>
<bean id="pet" class="com.msb.Pet">
<property name="name" value="kele"></property>
</bean>
实体
public class Person {
private String name;
private Pet pet;
}
public class Pet {
private String name;
}
可选两种类型
byName
byName方式自动注入:要求注入的bean的id必须和被注入的bean对象的属性名一致
byType
byType方式自动注入:要求注入的bean的对象类型与被注入的bean对象类型一致,并且在配置文件中的Bean相同类型必须唯一
如果存在多个,会抛异常:
No qualifying bean of type 'com.msb.Pet' available: expected single matching bean but found 2: pet,pet2
全局自动注入
在首行Beans标签下添加default-autowire属性。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byType"
>
annotation注解注入
使用注解需要导入AOP包
在配置文件中添加Context约束
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
"
>
context:component-scan
<context:component-scan base-package="com.msb"></context:component-scan>
component-scan可以自动扫描包内容,并注册Bean到Spring容器
@Component
在需要注册到容器的类上添加@Component标签,标识这个类由Spring容器接管
约定大于配置
在一个类上添加@Component默认会使用首字母小写的类名作为ID注册到Spring容器。
如果需要手动指定Bean Id可以使用@Component("p")
同属@Component的额外三个注解
@Controller @Service @Repository
这三个注意在MVC开发中会经常用到,除了注解名字和Component不一样之外,其余功能都一样。
Spring额外提供这三个注解的目的主要是为了区分MVC中每个类的区别。
@Scope
使用注解注册Bean 默认的作用域还是singleton,可以使用@Scope("prototype")改变对象作用域
@Value
在使用注解给对象注入值的时候,不再需要Get/Set方法
基础类型
使用@Value注解
@Value("小明")
private String name;
对象引用
@Autowired
private Pet MyPet;
使用@Autowired注解
默认是ByType的,如果需要ByName需要配合@Qualifier注解
@Autowired()
@Qualifier("p2")
private Pet MyPet;
面向切面编程 代码增强
AOP(Aspect Oriented Programming)面向切面编程。
面向切面,是与OOP(Object Oriented Programming)面向对象编程并列的编程思想。
Spring支持两种方法,那么我们在使用spring进行动态代理时究竟使用的哪一种方法呢?spring优先支持实现接口的方式,如果没有接口则使用cglib方式
代理
通过代理可以隐藏目标类的具体实现;在不修改目标类代码的情况下能够对其功能进行增强。
- 委托类和代理类有相同的接口或者共同的父类
- 代理类为委托类负责处理消息,并将消息转发给委托类
- 委托类和代理类对象通常存在关联关系
- 一个代理类对象与一个委托类对象关联
- 代理类本身并不是真正的实现者!而是通过调用委托类的方法来实现功能!
静态代理
使用硬编码的方式增强原有方法
- 优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
- 缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。
Girl -> 目标对象 -> 被包装/增强的对象
public class Girl implements Human{
public void eat() {
System.out.println("Em mmm.. mm..");
}
}
抽象接口
interface Human {
public void eat();
}
ProxyGirl 代理对象,包含对原对象方法的增强,通过构造方法传入原对象,并实现和原对象相同的接口,实现接口方法,便可以利用Java多态的特性,通过访问代理方法同时能够调起原对象的实现,并对其增强。
public class ProxyGirl implements Human {
private Human human;
public ProxyGirl() {
super();
}
public ProxyGirl(Human human) {
super();
this.human = human;
}
public void eat() {
System.out.println("chiqian");
human.eat();
System.out.println("chihou");
}
}
测试类
Girl girl = new Girl();
Human proxyGirl = new ProxyGirl(girl);
proxyGirl.eat();
动态代理
动态代理是指动态的在内存中构建代理对象(需要我们制定要代理的目标对象实现的接口类型),即利用JDK的API生成指定接口的对象,也称之为JDK代理或者接口代理。
- 目标对象实现了接口 JDK动态代理
- 目标对象没有实现口CGLib
JDK动态代理
CGLIB动态代理
底层ASM
《SpringBoot 2.x》入门:框架介绍与HelloWorld
-
MVC架构思想
-
使用STS构建SpringBoot项目
-
使用SpringBoot构建Mvc web项目
-
MVCWeb项目中的注入
-
热部署
介绍
SpringBoot主要解决的是在微服务的架构下简化配置(有快速配置)、前后端分离、快速开发
优点:
-
提供了快速启动入门
-
开箱即用、提供默认配置
-
内嵌容器化web项目
-
没有冗余代码生成和xml配置要求
2.运行Demo
创建项目
创建SpringBoot项目的几种方式:
-
官网的Initializr
-
使用Eclipse、STS、Idea等IDE创建Maven项目并引入依赖
-
使用STS插件的Spring Initializr创建项目
访问http://start.spring.io/ 进入Spring项目Initializr
生成下载demo.zip
导入项目
1.Import一个Maven项目
2.选择要导入的文件
3.项目骨架
启动项目
-
直接run启动程序里的Main()方法
-
安装过STS插件或使用STS可以在项目上右键RunAS->Spring Boot APP
运行成功提示信息:
如果运行报错,请参照常见问题。
个性化
修改启动banner
在resources目录下新建banner.txt
http://www.network-science.de/ascii/ 英文
https://www.degraeve.com/img2txt.php 图片
Eclipse的皮肤
菜单栏中
Help -> EclipseMarketplace
搜索Theme
傻瓜式安装这个,安装完成会提示重启,跟随指引选择喜欢的风格。
简单使用
application.properties
把所有的配置全放在这个文件里,方便统一管理,maven也可以做到
修改tomcat端口
server.port=90
修改项目路径
server.servlet.context-path=/demo
多个入口main方法,打包之后找不到入库类
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.mashibing.MyApp</mainClass>
</configuration>
</plugin>
</plugins>
</build>
HelloWorld
RestController
RestController = @Controller+@ResponseBody
一个效果
@RestController
public class MyAppController {
@RequestMapping("/")
public Map<String, String> index() {
Map<String, String> map = new HashMap<>();
map.put("aaa", "bbb");
map.put("aaa", "bbb");
map.put("aaa", "bbb");
map.put("aaa", "bbb");
return map;
}
使用thymeleaf模板引擎
Pom.xml引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Controller代码
@Controller
public class IndexController {
@RequestMapping("/")
public String index(ModelMap map) {
// 加入一个属性,用来在模板中读取
map.addAttribute("msg", "nihao~");
return模板文件的名称,对应src/main/resources/templates/index.html
return "index";
}
模板文件代码
<h1 th:text="${msg}">hi!</h1>
稍微复杂的restful api应用
UserRestfulController
UserRestfulController
@RequestMapping("/")
@RestController
public class UserRestfulController {
static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long,User>());
@RequestMapping(value="/User",method=RequestMethod.GET)
public List<User> getUserList(){
ArrayList<User> list = new ArrayList<>(users.values());
return list;
}
@RequestMapping(value="User",method=RequestMethod.POST)
public String addUser(@ModelAttribute User user) {
users.put(user.getId(), user);
return "addUser Success";
}
}
User
public class User {
private Long id;
private String loginName;
private String password;
private String nickName;
注入Service
UserRestfulController
@Autowired
private UserService userSrv;
@RequestMapping(value="/User",method=RequestMethod.GET)
public List<User> getUserList(){
return userSrv.getUserList();
}
@RequestMapping(value="User",method=RequestMethod.POST)
public String addUser(@ModelAttribute User user) {
String msg = userSrv.addUser(user);
return msg;
}
UserService
@Service
public class UserService {
static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long,User>());
public List<User> getUserList() {
ArrayList<User> list = new ArrayList<>(users.values());
return list;
}
public String addUser(User user) {
users.put(user.getId(), user);
return "addUser Success";
}
}
前端模板显示
<h1>User list</h1>
<table>
<tr>
<th>NAME</th>
<th>loginName</th>
<th>nickName</th>
</tr>
<tr th:each="user : ${list}">
<td th:text="${user.id}">id</td>
<td th:text="${user.loginName}">loginName</td>
<td th:text="${user.nickName}">nickName</td>
</tr>
</table>
<p>
<a href="../home.html" th:href="@{/}">Return to home</a>
</p>
常见问题
Pom.xml
Springboot项目必须要继承的parnet
Pom.xml第一行报错
进入本地库
for /r %i in (*.lastUpdated) do del %i
然后update
缺少或包错误
删掉 重新update
找不到主类
所有错误都解决后
Jar方式运行 首先得有这个jar包
先clean package 生成jar文件,然后再run main方法
找不到jdk
把jre的路径换成jdk的
启动后自动停止
《Spring Boot 2.x》表单提交与服务器端数据校验
静态资源访问
src/main/resources/static
src/main/webapp
视图层整合
Jsp
Pom
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
Properties
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table border="1" align="center" width="50%">
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
<c:forEach items="${list }" var="user">
<tr>
<td>${user.userid }</td>
<td>${user.username }</td>
<td>${user.userage }</td>
</tr>
</c:forEach>
</table>
</body>
</html>
Controller
@Controller
public class UserController {
/*
* 处理请求,产生数据
*/
@RequestMapping("/showUser")
public String showUser(Model model){
List<Users> list = new ArrayList<>();
list.add(new Users(1,"张三",20));
list.add(new Users(2,"李四",22));
list.add(new Users(3,"王五",24));
//需要一个Model对象
model.addAttribute("list", list);
//跳转视图
return "userList";
}
整合DAO层
Spring-data-jpa
Entity
<h1>User list</h1>
<table>
<tr>
<th>NAME</th>
<th>loginName</th>
<th>nickName</th>
</tr>
<tr th:each="city : ${list}">
<td th:text="${city.id}">id</td>
<td th:text="${city.name}">loginName</td>
</tr>
</table>
<p>
<a href="../home.html" th:href="@{/}">Return to home</a>
</p>
Repository
public interface CityRepository extends JpaRepository<City, Integer> {
}
Properties
##端口号
server.port=8888
##数据库配置
##数据库地址
spring.datasource.url=jdbc:mysql://localhost:3306/erp?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
##数据库用户名
spring.datasource.username=root
##数据库密码
spring.datasource.password=840416
##数据库驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
##validate 加载hibernate时,验证创建数据库表结构
##create 每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。
##create-drop 加载hibernate时创建,退出是删除表结构
##update 加载hibernate自动更新数据库结构
##validate 启动时验证表的结构,不会创建表
##none 启动时不做任何操作
#spring.jpa.hibernate.ddl-auto=validate
##控制台打印sql
spring.jpa.show-sql=true
spring.devtools.restart.enabled: true
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=UTF-8
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
spring.mvc.date-format=yyyy-MM-dd
pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Html
<h1>User list</h1>
<table>
<tr>
<th>NAME</th>
<th>loginName</th>
<th>nickName</th>
</tr>
<tr th:each="city : ${list}">
<td th:text="${city.id}">id</td>
<td th:text="${city.name}">loginName</td>
</tr>
</table>
<p>
<a href="../home.html" th:href="@{/}">Return to home</a>
</p>
《Spring Boot 2.x》SpringDataJpa 与ThymeLeaf
SpringBoot整合
整合Servlet
注解方式
启动类上添加注解
@SpringBootApplication
@ServletComponentScan
public class Springboot011Application {
public static void main(String[] args) {
SpringApplication.run(Springboot011Application.class, args);
}
}
Servlet类
@WebServlet(name = "myServlet",urlPatterns = "/srv",loadOnStartup = 1)
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("111");
super.doGet(req, resp);
}
}
编码方式
启动类中添加
@Bean
public ServletRegistrationBean<MyServlet2> getServletRegistrationBean(){
ServletRegistrationBean<MyServlet2> bean = new ServletRegistrationBean<>(new MyServlet2(), "/s2");
bean.setLoadOnStartup(1);
return bean;
}
Servlet
无需注解
整合Filter
implements Filter
过滤器
同Servlet
Listener
监听器
MyListener implements ServletContextListener
同上
静态资源访问
src/main/resources/static
src/main/webapp
SpringBoot文件上传
指定大小
spring.http.multipart.maxFileSize=200MB
spring.http.multipart.maxRequestSize=200MB
spring.servlet.multipart.max-request-size = 200MB
spring.servlet.multipart.max-file-size = 200MB
表单
<form action="fileUploadController" method="post" enctype="multipart/form-data">
上传文件:<input type="file" name="filename"/><br/>
<input type="submit"/>
</form>
Controller
@RequestMapping("/fileUploadController")
public String fileUpload(MultipartFile filename) throws Exception{
System.out.println(filename.getOriginalFilename());
filename.transferTo(new File("e:/"+filename.getOriginalFilename()));
return "ok";
}
表单数据接收
@GetMapping(value = "/hello/{id}")
public String hello(@PathVariable("id") Integer id){
return "ID:" + id;
}
@PostMapping(value = "/user-2")
public User saveUser2(@RequestBody User user) {
return user;
}
@PostMapping(value = "/post")
public String post(@RequestParam(name = "name") String name,
@RequestParam(name = "age") Integer age) {
String content = String.format("name = %s,age = %d", name, age);
return content;
}
SpringData Jpa进阶使用
显示SQL
spring.jpa.show-sql=true
自定义查询
自定义接口
- And --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);
- Or --- 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);
- Between --- 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min);
- LessThan --- 等价于 SQL 中的 "<",比如 findBySalaryLessThan(int max);
- GreaterThan --- 等价于 SQL 中的">",比如 findBySalaryGreaterThan(int min);
- IsNull --- 等价于 SQL 中的 "is null",比如 findByUsernameIsNull();
- IsNotNull --- 等价于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();
- NotNull --- 与 IsNotNull 等价;
- Like --- 等价于 SQL 中的 "like",比如 findByUsernameLike(String user);
- NotLike --- 等价于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);
- OrderBy --- 等价于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);
- Not --- 等价于 SQL 中的 "! =",比如 findByUsernameNot(String user);
- In --- 等价于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
- NotIn --- 等价于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
自定义SQL@Query
占位符
public interface UserDao extends Repository<AccountInfo, Long> {
@Query("select a from AccountInfo a where a.accountId = ?1")
public AccountInfo findByAccountId(Long accountId);
@Query("select a from AccountInfo a where a.balance > ?1")
public Page<AccountInfo> findByBalanceGreaterThan(
Integer balance,Pageable pageable);
}
参数名
public interface UserDao extends Repository<AccountInfo, Long> {
public AccountInfo save(AccountInfo accountInfo);
@Query("from AccountInfo a where a.accountId = :id")
public AccountInfo findByAccountId(@Param("id")Long accountId);
@Query("from AccountInfo a where a.balance > :balance")
public Page<AccountInfo> findByBalanceGreaterThan(
@Param("balance")Integer balance,Pageable pageable);
}
更新
@Modifying
@Query("update AccountInfo a set a.salary = ?1 where a.salary < ?2")
public int increaseSalary(int after, int before);
直接使用Native SQL
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
Thymeleaf
编辑插件
安装地址:
<html xmlns:th="http://www.thymeleaf.org">
URL地址
在应用上下文内
1)@{userList} 相对当前路径结果为:http://localhost/thymeleaf/user/userList
2)@{./userList} 相对当前路径结果为:http://localhost/thymeleaf/user/userList
3)@{../tiger/home} 相对当前路径结果为:http://localhost/thymeleaf/tiger/home
4)@{/tiger/home} 相对应用根目录结果为:http://localhost/thymeleaf/tiger/home
5)@{https://www.baidu.com/} 绝对路径结果为:https://www.baidu.com
6)<link type="text/css" rel="stylesheet" th:href="@{/css/home.css}">,@ 以 "/" 开头相对应用根目录,否则是相对当
Href
<body>
<a th:href="@{userList(id=9527)}">1、@{userList(id=9527)}</a>
<a th:href="@{userList(id=9527,name=华安)}">2、@{userList(id=9527,name=华安)}</a>
<a th:href="@{userList(id=9527,name=${userName})}">3、@{userList(id=9527,name=${userName})}</a>
</body>
文本
<!--空格属于特殊字符,必须使用单引号包含整个字符串-->
<p class="css1 css2" th:class="'css1 css2'">样式</p>
<!--下面如果没用单引号 th:text="Big China",则页面直接报错-->
<p th:text="'Big China'">中国</p>
<!--后台使用:model.addAttribute("info", "Love you 中国"); 传值有空格也是没有问题的-->
<p th:text="${userName}">userName</p>
<!--后台传值字符串有空格是可以的,可以使用 + 进行字符串连接-->
<p th:text="'small smile'+',very good.' + ${userName}">浅浅的微笑</p>
数字计算
<p th:text="80">8</p>
<!--计算结果为 16 在进行替换-->
<p th:text="8+8">8 + 8</p>
<!--前面 8+8 计算结果为 16,然后字符串拼接上 Love,后面的 9+9也会被当做字符串拼接-->
<p th:text="8+8+' Love '+9+9">8 + 8+' Love '+9+9</p>
<!--前面 8+8 计算结果为 16,后面的 9+9因为有括号,所以也会计算结果,最后拼接 Love 字符串-->
<p th:text="8+8+' Love '+(9+9)">8 + 8+' Love '+(9+9)</p>
<!--后台传了一个:model.addAttribute("age", 35);取得结果后在进行计算-->
<p th:text="100-${age}"></p>
Boolean判断
<p th:text="true">布尔</p>
<!--true、false 是布尔值,and 是布尔运行符,and(与),or(或),not(非)、!(非)-->
<p th:text="true and false">true and true</p>
<!--后台使用 model.addAttribute("isMarry", true); 传了值-->
<!--th:if 表达式为 true,则显示标签内容,否则不显示-->
<p th:if="${isMarry}">已结婚</p>
<!--后台传值:model.addAttribute("age", 35);-->
<!--比较运算符:>,<,> =,<=(gt,lt,ge,le)-->
<p th:if="${age}>18">已成年</p>
<p th:if="${age}<18">未成年</p>
运算
<p th:text="15 * 4">值为 60 </p>
<p th:text="15 * 4-100/10">值为 50 </p>
<p th:text="100 % 8">值为 4</p>
比较
<p th:if="5>3">5 大于 3</p>
<p th:if="5 >4">5 大于 4</p>
<p th:if="10>=8 and 7 !=8">10大于等于8,且 7 不等于 8 </p>
<p th:if="!${isMarry}">!false</p>
<p th:if="not(${isMarry})">not(false)</p>
三元运算符
<p th:text="7>5?'7大':'5大'">三元运算符</p>
<!--后台控制器输出了:model.addAttribute("age", 35);-->
<!--因为 ${xx}取值时,如果值为null,则默认整个标签不再显示-->
<p th:text="${age}!=null?${age}:'age等于 null'"></p>
<!--这里使用嵌套判断,嵌套的部分要使用括号-->
<p th:text="${age}!=null?(${age}>=18?'成年':'未成年'):'age等于 null'"></p>
<!--变量 age2 后台并没有输出,所以 age2 不存在,此时 age2 ==null-->
<p th:text="${age2}!=null?${age2}:'age2等于 null'"></p>
<!--后台输出了:model.addAttribute("isMarry", true);-->
<!--A>B?X:Y,这里的 Y 部分是省略的,此时如果 A>B 返回 false,则整个三元运算结果为 null-->
<p th:class="${isMarry}?'css2':'css3'">已婚</p>
TH标签
th:utext转义
map .addAttribute("china", "<b>Chian</b>,USA,UK");
<p th:text="${china}">默认转义</p>
<!--th:utext 不会结果进行转义-->
<p th:utext="${china}">不会转义</p>
th:attr 设置属性
HTML5 所有的属性,都可以使用 th:* 的形式进行设置值
<a href="http://baidu.com" th:attr="title='百度'">百度</a>
<!--设置 title、href 多个属性-->
<a href="" th:attr="title='前往百度',href='http://baidu.com'">前往百度</a>
<!--设置 href 属性-->
<a href="userList.html" th:attr="href=@{/user/userHome}">用户首页</a>
<!--设置 id 属性,data-schoolName 属性 Html 本身是没有的,但允许用户自定义 -->
<a href="#" th:attr="id='9527',data-target='user'">归海一刀</a>
<p th:abc="9527">th:abc="9527"</p>
<!--输出:<p abc123="华安">th:abc123="华安"</p>-->
<p th:abc123="华安">th:abc123="华安"</p>
Checked selected
<input type="checkbox" name="option1" checked/><span>是否已婚1?</span>
<input type="checkbox" name="option2" checked="checked"/><span>是否已婚2?</span>
---<br>
<!--后台控制器传递了一个:model.addAttribute("isMarry", true);-->
<!--option3、option4 会选中;option5 不会选中-->
<input type="checkbox" name="option3" th:checked="${isMarry}"/><span>是否已婚3?</span>
<input type="radio" name="option4" th:checked="${isMarry}"/><span>是否本科?</span>
<input type="radio" name="option5" th:checked="!${isMarry}"/><span>是否应届生?</span>
---------------------
<select>
<option>a</option>
<option th:selected="${isMarry}">已婚</option>
<option th:selected="${!isMarry}">未婚</option>
</select>
<input type="text" th:autofocus="false">
<input type="text" th:autofocus="true">
<input type="text" th:autofocus="false">
日期格式化
<span th:text="${#dates.format(date, 'yyyy-MM-dd HH:mm')}"></span>
循环
JSTL 有一个 <c:foreach>,同理 Thymeleaf 也有一个 th:each。作用都是一样的,都是用于遍历数组、List、Set、Map 等数据。
在Select上循环
<option th:each="city : ${list}" th:text="${city.name}" th:selected="${cityName} eq ${city.name}">横岗</option>
状态变量loopStatus
如果不指定 为变量+Stat
- index: 当前迭代对象的index(从0开始计算)
- count: 当前迭代对象的index(从1开始计算)
- size: 被迭代对象的大小 current:当前迭代变量
- even/odd: 布尔值,当前循环是否是偶数/奇数(从0开始计算)
- first: 布尔值,当前循环是否是第一个
- last: 布尔值,当前循环是否是最后一个
<tr th:each="city,status : ${list}" th:style="${status.odd}?'background-color:#c2c2c2'">
<!-- EL JSTL-->
<td th:text = "${status.count}"></td>
<td th:text = "${city.id}"></td>
<td th:text = "${city.name}"></td>
</tr>
If/else
<p th:if="${isMarry}">已婚1</p>
<p th:unless="${isMarry}">未婚</p>
Switch/case 多条件判断
<div th:switch="1">
<p th:case="0">管理员</p>
<p th:case="1">操作员</p>
<p th:case="*">未知用户</p>
</div>
<!--数字类型:当没有 case 匹配时,取默认值,当有多个匹配,只取第一个-->
<div th:switch="-1">
<p th:case="0">管理员</p>
<p th:case="*">操作员</p>
<p th:case="*">未知用户</p>
</div>
<!--布尔类型,多个case满足时,只取第一个-->
<div th:switch="${isMarry}">
<p th:case="true">已婚</p>
<p th:case="true">已成年</p>
<p th:case="false">未婚</p>
</div>
<!--字符串类型-->
<div th:switch="'For China'">
<p th:case="'For USA'">美国</p>
<p th:case="'For UK'">英国</p>
<p th:case="'For China'">中国</p>
<p th:case="*">未知国籍</p>
</div>
内联表达式
[[...]] 等价于 th:text(结果将被 HTML 转义),[(...)] 等价于 th:utext(结果不会执⾏HTML转义)
<p>[[${china}]]</p>
<p>[(${china})]</p>
<p>[[Lo1ve]]</p>
<p>[['I Love You Baby']]</p>
<p>[(9527)]</p>
th:inline =“none” 来禁⽤内联。
内联 JavaScript
<script type="text/javascript" th:inline="javascript">
var info = [[${info}]];
var age = [[${age}]];
var id = [[${id}]];
var name = [[${name}]];
console.log(id, name, age, info);
</script>
前后端分离
<script type="text/javascript" th:inline="javascript">
/**
* Thymeleaf 将自动忽略掉注释之后 和 分号之前的所有内容,如下为 "前端测试"
*/
var info = /*[[${info}]]*/ "前端测试";
console.log(info);
</script>
对象属性
URL
<p>${param.size()}=[[${param.size()}]]</p>
<!--/*判断请求参数是否为空*/-->
<p>${param.isEmpty()}=[[${param.isEmpty()}]]</p>
<!--获取某个参数值,不存在时为null-->
<p>${param.u_id}=[[${param.u_id}]]</p>
Session
<p>${session.size()}=[[${session.size()}]]</p>
<!--/*判断请求参数是否为空*/-->
<p>${session.isEmpty()}=[[${session.isEmpty()}]]</p>
<!--获取某个参数值,不存在时为null-->
<p>${session.user.id}=[[${session.user.id}]]</p>
完整文档
https://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#base-objects
mybatis
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
配置文件
MybatisConfig.xml
SSM中需要配置
-
数据url
-
数据库连接池
-
映射文件
-
事务
在SpringBoot中整合到property中了
Mapper.xml
namespace
接口绑定 和接口
就可以不用写DAO实现类,Mybatis会通过绑定自动找到要执行的sql语句。
resultMap
结果集对应到实体类的字段到属性映射
xml 方式
传统方式
xml配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!-- version: $Id$ --> <configuration> <!-- 引用JDBC属性的配置文件 --> <properties resource="database.properties" /> <environments default="development"> <environment id="development"> <!-- 使用JDBC的事务管理 --> <transactionManager type="JDBC" /> <!-- POOLED :JDBC连接对象的数据源连接池的实现,不直接支持第三方数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="${database.driver}" /> <property name="url" value="${database.url}" /> <property name="username" value="${database.username}" /> <property name="password" value="${database.password}" /> </dataSource> </environment> </environments> <!-- ORM映射文件 --> <mappers> <!-- 注解的方式 --> <mapper class="com.iflytek.dao.mapper.AccountMapper" /> <!-- XML的方式 --> <mapper resource="com/mashibing/dao/xml/AccountMapper.xml" /> <!-- 这里对于注解,还可以通过<package name="com.mashibing.dao.mapper"/> --> </mappers> </configuration>
Service 配置
public class AccountService { public boolean insertAccount(Account account) { boolean flag = false; SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession(); try { accountMapper accountMapper = sqlSession.getMapper(AccountMapper.class); int result = accountMapper.insert(student); if (result > 0) { flag = true; } sqlSession.commit(); } finally { sqlSession.close(); } return flag; } public Student getAccountById(int id) { SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession(); try { AccountMapper AccountMapper = sqlSession.getMapper(AccountMapper.class); return AccountMapper.selectByPrimaryKey(id); } finally { sqlSession.close(); } } public List<Student> getAllStudents() { SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession(); try { StudentMapper StudentMapper = sqlSession.getMapper(StudentMapper.class); return StudentMapper.selectByExample(new StudentExample()); } finally { sqlSession.close(); } } public boolean updateAccount(Account account) { SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession(); boolean flag = false; try { AccountMapper AccountMapper = sqlSession.getMapper(AccountMapper.class); int result = AccountMapper.updateByPrimaryKey(Account); if (result > 0) { flag = true; } sqlSession.commit(); } finally { sqlSession.close(); } return flag; } public boolean deleteAccount(int id) { SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession(); boolean flag = false; try { AccountMapper AccountMapper = sqlSession.getMapper(AccountMapper.class); int result = AccountMapper.deleteByPrimaryKey(id); if (result > 0) { flag = true; } sqlSession.commit(); } finally { sqlSession.close(); } return flag; } }
与SpringBoot整合
引入依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>springboot03-mybatis</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot03-mybatis</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
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.mashibing.springboot.mapper.AccountMapper"> <resultMap type="com.mashibing.springboot.mapper.Account" id="BaseResultMap"> <result column="login_name" property="loginName"/> <result column="password" property="password"/> </resultMap> <insert id="save" parameterType="Account"> INSERT INTO account(login_name,password) VALUES ( #{loginName},#{password} ) </insert> <select id="findAll" resultMap="BaseResultMap"> select * from account </select> </mapper>
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=UTC ##数据库用户名 spring.datasource.username=root ##数据库密码 spring.datasource.password=840416 # 用来实例化mapper接口 mybatis.type-aliases-package=com.mashibing.springboot.mapper # 对应的sql映射 mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
AccountMapper
package com.mashibing.springboot.mapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface AccountMapper { void save(Account account); }
Account
public class Account { private int id; private String loginName; private String password; private String nickName; private int age; private String location; private int banlance; public int getId() {
显示日志
logging.level.com.mashibing.springboot.mapper=debug
注解查询
@Select("select * from account1") List<Account> findAll();
查找mapper接口
在入口加入 MapperScan
@MapperScan("com.mashibing.springboot.mapper") public class Springboot03MybatisApplication {
每一个mapper接口上加入
@Mapper public interface AccountMapper {
Mapper 自动生成
eclipse插件 市场搜素
MyBatis Generator
图形化
https://github.com/zouzg/mybatis-generator-gui
分页查询
依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.12</version> </dependency>
Service
public Object findPage(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); AccountExample example = new AccountExample(); return mapper.selectByExample(example ); }