SpringBoot
- 为什么要使用 Spring Boot
- 因为Spring, SpringMVC 需要使用的大量的配置文件 (xml文件)还需要配置各种对象,把使用的对象放入到spring容器中才能使用对象,需要了解其他框架配置规则。
- SpringBoot 就相当于 不需要配置文件的Spring+SpringMVC。 常用的框架和第三方库都已经配置好了。
一、xml和 JavaConfig
- Spring 使用 Xml 作为容器配置文件, 在 3.0 以后加入了 JavaConfig. 使用 java 类做配置文件使用。
1、 JavaConfig
- JavaConfig: 是 Spring 提供的使用 java 类配置容器。 配置 Spring IOC 容器的纯 Java 方法。
- 优点:
- 可以使用面向对象的方式, 一个配置类可以继承配置类,可以重写方法
- 避免繁琐的 xml 配置
2、使用 :
- @Configuration :放在一个类的上面,表示这个类是作为配置文件使用的。
- @Bean:声明对象,把对象注入到容器中。
- 不指定对象的名称,默认方法名是id
package com.cooler.config;
import com.cooler.vo.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author CoolEr
* @create 2022/3/21
*/
@Configuration
public class SpringConfig {
/**
* 创建方法,方法的返回值是对象。
* 方法的返回值对象就注入到容器中
*/
@Bean
// @Bean(name = "zsStudent")
public Student createStudent(){
Student s1 = new Student();
s1.setName("张三");
s1.setAge(20);
s1.setSex("男");
return s1;
}
}
测试:
import com.cooler.config.SpringConfig;
import com.cooler.vo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author CoolEr
* @create 2022/3/21
*/
public class MyTest {
@Test
public void test01(){
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
Student student = (Student) ctx.getBean("createStudent");
System.out.println(student);
}
}
3、@ImportResource
- @ImportResource 作用导入其他的xml配置文件, 等于在xml <import resources=“其他配置文件”/>
@Configuration
@ImportResource(value ={ "classpath:applicationContext.xml","classpath:beans.xml"})
public class SpringConfig {
}
4、@PropertyResource
- @PropertyResource 是读取 properties 属性配置文件,在程序代码之外提供数据。
- 步骤:
- 在resources目录下,创建properties文件, 使用k=v的格式提供数据
- 在PropertyResource 指定properties文件的位置
- 使用@Value(value=“${key}”)
@Configuration
@ImportResource(value ={ "classpath:applicationContext.xml","classpath:beans.xml"})
@PropertySource(value = "classpath:config.properties")
@ComponentScan(basePackages = "com.cooler.vo")
public class SpringConfig {
}
以上两个注解使用具体代码
<?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: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 https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="myCat" class="com.cooler.vo.Cat">
<property name="name" value="tom猫"/>
<property name="age" value="2" />
<property name="cardId" value="uw532423422"/>
</bean>
<!-- <context:property-placeholder location="classpath:config.properties" />
<context:component-scan base-package="com.cooler.vo" />
<import resource="classpath:beans.xml" />-->
</beans>
@Configuration
@ImportResource(value ={ "classpath:applicationContext.xml","classpath:beans.xml"})
@PropertySource(value = "classpath:config.properties")
@ComponentScan(basePackages = "com.cooler.vo")
public class SpringConfig {
/**
* 创建方法,方法的返回值是对象。 在方法的上面加入@Bean
* 方法的返回值对象就注入到容器中。
*
* @Bean: 把对象注入到spring容器中。 作用相当于<bean>
*
* 位置:方法的上面
*
* 说明:@Bean,不指定对象的名称,默认是方法名是 id
*
*/
@Bean
public Student createStudent(){
Student s1 = new Student();
s1.setName("张三");
s1.setAge(26);
s1.setSex("男");
return s1;
}
/***
* 指定对象在容器中的名称(指定<bean>的id属性)
* @Bean的name属性,指定对象的名称(id)
*/
@Bean(name = "lisiStudent")
public Student makeStudent(){
Student s2 = new Student();
s2.setName("李四");
s2.setAge(22);
s2.setSex("男");
return s2;
}
tiger.name=\u4E1C\u5317\u8001\u864E
tiger.age=3
@Component("tiger")
public class Tiger {
@Value("${tiger.name}")
private String name;
@Value("${tiger.age}")
private Integer age;
@Override
public String toString() {
return "Tiger{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
二、SpringBoot
1、SpringBoot概述
-
SpringBoot是Spring中的一个成员, 可以简化Spring,SpringMVC的使用。 他的核心还是IOC容器。
-
特点:
-
Create stand-alone Spring applications——创建spring应用
-
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)——内嵌的tomcat, jetty , Undertow
-
Provide opinionated ‘starter’ dependencies to simplify your build configuration——提供了starter起步依赖,简化应用的配置。
- 比如使用MyBatis框架 , 需要在Spring项目中,配置MyBatis的对象 SqlSessionFactory , Dao的代理对象在SpringBoot项目中,在pom.xml里面, 加入一个 mybatis-spring-boot-starter依赖
-
Automatically configure Spring and 3rd party libraries whenever possible——尽可能去配置spring和第三方库。叫做自动配置(就是把spring中的,第三方库中的对象都创建好,放到容器中, 开发人员可以直接使用)
-
Provide production-ready features such as metrics, health checks, and externalized configuration——提供了健康检查, 统计,外部化配置
-
Absolutely no code generation and no requirement for XML configuration——不用生成代码, 不用使用xml做配置
-
2、创建SpringBoot项目
(1)第一种方式
- 使用spring boot提供的初始化器,就是向导创建SpringBoot应用
- 使用的地址: https://start.spring.io
(2)第二种方式
- 使用国内的地址:https://start.springboot.io
(3)第三种方式
- 使用 maven 向导创建项目
(4)基于springboot的web例子
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cooler</groupId>
<artifactId>005-springboot-mvc</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web起步依赖(springmvc功能)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@Controller
public class HelloSpringBoot {
@RequestMapping("/hello")
@ResponseBody
public String helloSpringBoot(){
return "欢迎使用SpringBoot框架";
}
}
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3、注解@SpringBootApplication
- 复合注解:由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan组成
- @SpringBootConfiguration
- 使用了@SpringBootConfiguration注解标注的类,可以作为配置文件使用的,可以使用Bean声明对象,注入到容器
- @EnableAutoConfiguration
- 启用自动配置, 把java对象配置好,注入到spring容器中。例如可以把mybatis的对象创建好,放入到容器中
- @ComponentScan
- @ComponentScan 扫描器,找到注解,根据注解的功能创建对象,给属性赋值等等。
- 默认扫描的包: @ComponentScan所在的类所在的包和子包。
- @SpringBootConfiguration
4、SpringBoot配置文件
- Spring Boot 的核心配置文件用于配置 Spring Boot 程序,名字必须以 application 开始
- 配置文件名称: application,扩展名有:
- properties( k=v)
- yml ( k: v)
(1)使用application.properties, application.yml
-
有两种格式的配置文件的情况下,默认使用properties
-
例1:application.properties设置 端口和上下文
#设置端口号
server.port=8082
#设置访问应用上下文路径, contextpath
server.servlet.context-path=/myboot
- 例2: application.yml
server:
port: 8083
servlet:
context-path: /myboot2
(2)多环境配置
- 有开发环境, 测试环境, 上线的环境。
- 每个环境有不同的配置信息, 例如端口, 上下文件, 数据库url,用户名,密码等等
- 使用多环境配置文件,可以方便的切换不同的配置。
- 使用方式: 创建多个配置文件, 名称规则: application-环境名称.properties(yml)
- 创建开发环境的配置文件: application-dev.properties( application-dev.yml )
- 创建测试者使用的配置: application-test.properties
#在主application.yml中激活使用的test环境
spring:
profiles:
active: test
5、SpringBoot自定义配置
(1)@value
- @Value(“${key}”) , key 来自 application.properties(yml)
@Controller
public class HelloController {
@Value("${server.port}")
private Integer port;
@Value("${server.servlet.context-path}")
private String contextPath;
@Value("${school.name}")
private String name;
@Value("${site}")
private String site;
@Resource
private SchoolInfo info;
@RequestMapping("/data")
@ResponseBody
public String queryData(){
return name+",site="+site+", 项目的访问地址="+contextPath+",使用的端口="+port;
}
@RequestMapping("/info")
@ResponseBody
public String queryInfo(){
return "SchoolInfo对象=="+info.toString();
}
}
#port
server.port=8082
#context-path
server.servlet.context-path=/myboot
school.name=Cooler
school.website=www.cooler.com
school.address=江西省
site=www.cooler.com
(2)@ConfigurationProperties
@Component
@ConfigurationProperties(prefix = "school")
public class SchoolInfo {
private String name;
private String website;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWebsite() {
return website;
}
public void setWebsite(String website) {
this.website = website;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "SchoolInfo{" +
"name='" + name + '\'' +
", website='" + website + '\'' +
", address='" + address + '\'' +
'}';
}
}
6、Spring Boot 中使用 JSP
-
SpringBoot不推荐使用jsp ,而是使用模板技术代替jsp
-
步骤:
- 加入一个处理jsp的依赖。 负责编译jsp文件
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cooler</groupId> <artifactId>009-springboot-jsp</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--处理jsp依赖--> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <!--指定jsp编译后的存放目录--> <resources> <resource> <!--jsp原来的目录--> <directory>src/main/webapp</directory> <!--指定编译后的存放目录--> <targetPath>META-INF/resources</targetPath> <!--指定处理的目录和文件--> <includes> <include>**/*.*</include> </includes> </resource> </resources> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
创建一个存放jsp的目录,一般叫做webapp—— index.jsp
-
需要在pom.xml指定jsp文件编译后的存放目录。
-
创建Controller, 访问jsp
@Controller public class JspController { /*public String doJsp(HttpServletRequest request){ request.setAttribute("data","SpringBoot使用Jsp"); //视图的逻辑名称 return "index"; }*/ @RequestMapping("/myjsp") public String doJsp(Model model){ //把数据放入到request作用域 model.addAttribute("data","SpringBoot使用Jsp"); //request.setAttribute("data","SpringBoot使用Jsp"); //视图的逻辑名称 return "index"; } }
- 在application.properties文件中配置视图解析器
#配置端口号 server.port=9090 server.servlet.context-path=/myboot #配置视图解析器 #/ = src/main/webapp spring.mvc.view.prefix=/ spring.mvc.view.suffix=.jsp
7、Spring Boot 中使用 ApplicationContext
- 在 main 方法中 SpringApplication.run()方法获取返回的 Spring 容器对象,再获取业务 bean进行调用。
- 多用在测试
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//获取容器对象
//ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
ApplicationContext ctx = SpringApplication.run(Application.class, args);
//从容器者获取对象
UserService userService = (UserService) ctx.getBean("userService");
userService.sayHello("李四");
}
}
8、 ComnandLineRunner 接口 , ApplicationRunner接口
- 开发中可能会有这样的情景。需要在容器启动后执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot 给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为 CommandLineRunner 和 ApplicationRunner。
- 他们的执行时机为容器启动完成的时候。这两个接口中有一个 run 方法,我们只需要实现这个方法即可。
- 这两个接口的不同之处在于: ApplicationRunner 中 run 方 法 的 参 数 为 ApplicationArguments , 而CommandLineRunner接口中 run 方法的参数为 String 数组
ComnandLineRunner 接口
@SpringBootApplication
public class Application implements CommandLineRunner {
@Resource
private HelloService helloService;
public static void main(String[] args) {
System.out.println("准备创建容器对象");
//创建容器对象
SpringApplication.run(Application.class, args);
System.out.println("容器对象创建之后");
}
@Override
public void run(String... args) throws Exception {
String str = helloService.sayHello("lisi");
System.out.println("调用容器中的对象="+str);
//可做自定义的操作,比如读取文件, 数据库等等
System.out.println("在容器对象创建好,执行的方法");
}
}
三、Spring Boot 和 web 组件
1、SpringBoot 中拦截器
-
拦截器是SpringMVC中一种对象,能拦截对Controller的请求。
-
框架中有系统的拦截器, 还可以自定义拦截器,实现对请求预先处理。
-
实现自定义拦截器步骤:
- 创建类实现SpringMVC框架的HandlerInterceptor接口
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
- 需在SpringMVC的配置文件中,声明拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:path="url" /> <bean class="拦截器类全限定名称"/> </mvc:interceptor> </mvc:interceptors>
springboot创建拦截器
/**
* 自定义拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
*
* @param request
* @param response
* @param handler 被拦截器的控制器对象
* @return boolean
* true: 请求能被Controller处理
* false: 请求被截断
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("执行了LoginInterceptor的preHandle");
return true;
}
}
@Configuration
public class MyAppConfig implements WebMvcConfigurer {
//添加拦截器对象, 注入到容器中
@Override
public void addInterceptors(InterceptorRegistry registry) {
//创建拦截器对象
HandlerInterceptor interceptor = new LoginInterceptor();
//指定拦截的请求uri地址
String path []= {"/user/**"};
//指定不拦截的地址
String excludePath [] = {"/user/login"};
registry.addInterceptor(interceptor)
.addPathPatterns(path)
.excludePathPatterns(excludePath);
}
}
2、使用servlet
-
使用步骤:
- 创建Servlet类,创建类继承HttpServlet
//创建Servlet类 public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //使用HttpServletResponse输出数据,应答结果 resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.println("===执行的是Servlet=="); out.flush(); out.close(); } }
- 注册Servlet ,让框架能找到Servlet
@Configuration public class WebApplictionConfig { //定义方法, 注册Servlet对象 @Bean public ServletRegistrationBean servletRegistrationBean(){ //public ServletRegistrationBean(T servlet, String... urlMappings) //第一个参数是 Servlet对象, 第二个是url地址 //这里是有参构造 //ServletRegistrationBean bean = //new ServletRegistrationBean( new MyServlet(),"/myservlet"); //这里是无参构造 ServletRegistrationBean bean = new ServletRegistrationBean(); bean.setServlet( new MyServlet()); bean.addUrlMappings("/login","/test"); // <url-pattern> return bean; } }
3、过滤器Filter
-
Filter是Servlet规范中的过滤器,可以处理请求, 对请求的参数, 属性进行调整。 常常在过滤器中处理字符编码
-
在框架中使用过滤器:
- 创建自定义过滤器类
// 自定义过滤器 public class MyFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("执行了MyFilter,doFilter "); filterChain.doFilter(servletRequest,servletResponse); } }
- 注册Filter过滤器对象
@Configuration public class WebApplicationConfig { @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter( new MyFilter()); bean.addUrlPatterns("/user/*"); return bean; } }
4、字符集过滤器
-
CharacterEncodingFilter : 解决post请求中乱码的问题
-
在SpringMVC框架, 在web.xml 注册过滤器,配置属性。
-
第一种方式:
-
使用步骤:
- 配置字符集过滤器
@Configuration public class WebSystemConfig { //注册Servlet @Bean public ServletRegistrationBean servletRegistrationBean(){ MyServlet myServlet = new MyServlet(); ServletRegistrationBean reg = new ServletRegistrationBean(myServlet,"/myservlet"); return reg; } //注册Filter @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean reg = new FilterRegistrationBean(); //使用框架中的过滤器类 CharacterEncodingFilter filter = new CharacterEncodingFilter(); //指定使用的编码方式 filter.setEncoding("utf-8"); //指定request , response都使用encoding的值 filter.setForceEncoding(true); reg.setFilter(filter); //指定 过滤的url地址 reg.addUrlPatterns("/*"); return reg; } }
- 修改application.properties文件, 让自定义的过滤器起作用
#SpringBoot中默认已经配置了CharacterEncodingFilter。 编码默认ISO-8859-1 #设置enabled=false 作用是关闭系统中配置好的过滤器, 使用自定义的CharacterEncodingFilter server.servlet.encoding.enabled=false
-
-
第二种方式
- 修改application.properties文件
server.port=9001 server.servlet.context-path=/myboot #让系统的CharacterEncdoingFilter生效 server.servlet.encoding.enabled=true #指定使用的编码方式 server.servlet.encoding.charset=utf-8 #强制request,response都使用charset属性的值 server.servlet.encoding.force=true
四、ORM 操作 MySQL
- 使用MyBatis框架操作数据, 在SpringBoot框架集成MyBatis
1、第一种方式@Mapper
-
@Mapper:放在dao接口的上面, 每个接口都需要使用这个注解。
-
使用步骤:
- mybatis起步依赖 : 完成mybatis对象自动配置, 对象放在容器中
- pom.xml 指定把src/main/java目录中的xml文件包含到classpath中
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cooler</groupId> <artifactId>017-springboot-mapper</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--weby起步依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mybatis起步依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!--mysql驱动--> <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> </dependencies> <build> <!--resources插件--> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- 创建实体类Student
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; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
- 创建Dao接口 StudentDao , 创建一个查询学生的方法
/** * @Mapper:告诉MyBatis这是dao接口,创建此接口的代理对象。 * 位置:在类的上面 */ @Mapper public interface StudentDao { Student selectById(@Param("stuId") Integer id); }
- 创建Dao接口对应的Mapper文件, xml文件, 写sql语句
<?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.cooler.dao.StudentDao"> <!--定义sql语句--> <select id="selectById" resultType="com.cooler.model.Student"> select id,name,age from student where id=#{stuId} </select> </mapper>
- 创建Service层对象, 创建StudentService接口和他的实现类。 去dao对象的方法。完成数据库的操作
public interface StudentService { Student queryStudent(Integer id); }
@Service public class StudentServiceImpl implements StudentService { @Resource private StudentDao studentDao; @Override public Student queryStudent(Integer id) { Student student = studentDao.selectById(id); return student; } }
- 创建Controller对象,访问Service。
@Controller public class StudentController { @Resource private StudentService studentService; @RequestMapping("/student/query") @ResponseBody public String queryStudent(Integer id){ Student student = studentService.queryStudent(id); return student.toString(); } }
- 写application.properties文件,配置数据库的连接信息。
server.port=9001 server.servlet.context-path=/orm #连接数据库:mysql驱动新版的驱动类 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123
- 测试
@SpringBootTest class ApplicationTests { @Test void contextLoads() { } }
2、@MapperSan
- 在 Dao 接口上面加入@Mapper,需要在每个接口都加入注解。当 Dao 接口多的时候不方便。可以使用如下的方式解决。
/**
* @MapperScan: 找到Dao接口和Mapper文件
* basePackages:Dao接口所在的包名
*/
@SpringBootApplication
@MapperScan(basePackages = {"com.cooler.dao","com.cooler.mapper"})
public class Application {
}
3、mapper 文件和 java 代码分开管理
-
mapper 文件放在 resources 目录下, java 代码放在 src/main/java。
- 在resources目录中创建子目录 (自定义的) , 例如mapper
- 把mapper文件放到 mapper目录中
- 在application.properties文件中,指定mapper文件的目录
#指定mapper文件的位置 mybatis.mapper-locations=classpath:mapper/*.xml #指定mybatis的日志 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
- 在pom.xml中指定 把resources目录中的文件 , 编译到目标目录中
<!--resources插件--> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> </resource> </resources>
4、事务支持
-
Spring框架中的事务:
- 管理事务的对象: 事务管理器(接口, 接口有很多的实现类)
- 例如:使用Jdbc或mybatis访问数据库,使用的事务管理器:DataSourceTransactionManager
- 管理事务的对象: 事务管理器(接口, 接口有很多的实现类)
-
声明式事务: 在xml配置文件或者使用注解说明事务控制的内容
- 控制事务: 隔离级别,传播行为, 超时时间
-
事务处理方式:
- Spring框架中的@Transactional
- aspectj框架可以在xml配置文件中,声明事务控制的内容
-
SpringBoot中使用事务: 上面的两种方式都可以。
- 第一步:在业务方法的上面加入@Transactional , 加入注解后,方法就有事务功能了。
- 第二步:明确的在主启动类的上面 ,加入@EnableTransactionManager
-
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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cooler</groupId>
<artifactId>019-springboot-transactional</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MyBatis起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</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>
</dependencies>
<build>
<!--处理资源目录-->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<!--mybatis代码自动生成插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<!--配置文件的位置: 在项目的根目录下,和src平级的-->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 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:\tools\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/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8"
userId="root"
password="123">
</jdbcConnection>
<!-- 生成model类,targetPackage指定model类的包名, targetProject指定生成的model放在eclipse的哪个工程下面-->
<javaModelGenerator targetPackage="com.cooler.model"
targetProject="D:\course\25-SpringBoot\springboot-prj\019-springboot-transactional\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="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- 生成MyBatis的Mapper接口类文件,targetPackage指定Mapper接口类的包名, targetProject指定生成的Mapper接口放在eclipse的哪个工程下面 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.cooler.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 数据库表名及对应的Java模型类名 -->
<table tableName="student" domainObjectName="Student"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false"/>
</context>
</generatorConfiguration>
- application.properties
#设置端口
server.port=9002
#context-path
server.servlet.context-path=/mytrans
#配置数据库
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123
#配置mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
#配置日志
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
- service实现类
@Service
public class StudentServiceImpl implements StudentService {
@Resource
private StudentMapper studentDao;
/**
* @Transactional: 表示方法的有事务支持
* 默认:使用库的隔离级别, REQUIRED 传播行为; 超时时间 -1
* 抛出运行时异常,回滚事务
*/
@Transactional
@Override
public int addStudent(Student student) {
System.out.println("业务方法addStudent");
int rows = studentDao.insert(student);
System.out.println("执行sql语句");
//抛出一个运行时异常, 目的是回滚事务
//int m = 10 / 0 ;
return rows;
}
}
- controller
@Controller
public class StudentController {
@Resource
private StudentService service;
@RequestMapping("/addStudent")
@ResponseBody
public String addStudent(String name,Integer age){
Student s1 = new Student();
s1.setName(name);
s1.setAge(age);
int rows = service.addStudent(s1);
return "添加学生:"+rows;
}
}
- Application
/**
* @EnableTransactionManagement: 启用事务管理器
*/
@SpringBootApplication
@EnableTransactionManagement
@MapperScan(basePackages = "com.cooler.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
五、接口架构风格—RESTful
- 接口: API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。 用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。
- 接口(API):可以指访问servlet,controller的url,调用其他程序的函数
1、REST
(1)概述
-
RESTful架构风格
- REST : (英文: Representational State Transfer , 中文: 表现层状态转移)。
- REST:是一种接口的架构风格和设计的理念,不是标准。
- 优点: 更简洁,更有层次
-
表现层状态转移:
- 表现层就是视图层, 显示资源的, 通过视图页面,jsp等等显示操作资源的结果。
- 状态: 资源变化
- 转移: 资源可以变化的。 资源能创建,new状态, 资源创建后可以查询资源, 能看到资源的内容,这个资源内容 ,可以被修改, 修改后资源 和之前的不一样。
-
URL加上请求方式必须唯一
(2)REST中的要素:
-
用REST表示资源和对资源的操作。
- 资源使用url表示的, 在互联网, 使用的图片,视频, 文本,网页等等都是资源。
- 资源是用名词表示。
比如我们要访问一个 http 接口:http://localhost:8080/boot/order?id=1021&status=1 采用 RESTFul 风格则 http 地址为:http://localhost:8080/boot/order/1021/1
-
对资源:
- 查询资源: 看,通过url找到资源。
- 创建资源: 添加资源
- 更新资源:更新资源 ,编辑
- 删除资源: 去除
-
使用http中的动作(请求方式), 表示对资源的操作(CURD)
- GET: 查询资源 – sql select
处理单个资源: 用他的单数方式 http://localhost:8080/myboot/student/1001 http://localhost:8080/myboot/student/1001/1 处理多个资源:使用复数形式 http://localhost:8080/myboot/students/1001/1002
- POST: 创建资源 – sql insert
http://localhost:8080/myboot/student 在post请求中传递数据 <form action="http://localhost:8080/myboot/student" method="post"> 姓名:<input type="text" name="name" /> 年龄:<input type="text" name="age" /> </form>
- PUT: 更新资源 – sql update(浏览器不直接支持)
<form action="http://localhost:8080/myboot/student/1" method="post"> 姓名:<input type="text" name="name" /> 年龄:<input type="text" name="age" /> <input type="hidden" name="_method" value="PUT" /> </form>
- DELETE: 删除资源 – sql delete
<a href="http://localhost:8080/myboot/student/1">删除1的数据</a>
-
需要的分页, 排序等参数,依然放在 url的后面, 例如
http://localhost:8080/myboot/students?page=1&pageSize=20
- 一句话说明REST: 使用url表示资源 ,使用http动作操作资源。
2、注解支持
- @PathVariable : 从url中获取数据
- @GetMapping: 支持的get请求方式,等同于 @RequestMapping( method=RequestMethod.GET)
- @PostMapping: 支持post请求方式 ,等同于 @RequestMapping( method=RequestMethod.POST)
- @PutMapping: 支持put请求方式,等同于 @RequestMapping( method=RequestMethod.PUT)
- @DeleteMapping: 支持delete请求方式,等同于 @RequestMapping( method=RequestMethod.DELETE)
- @RestController: 符合注解, 是@Controller和@ResponseBody组合。
- 在类的上面使用@RestController , 表示当前类者的所有方法都加入了 @ResponseBody
@RestController
public class MyRestController {
// 学习注解的使用
//查询id=1001的学生
/**
* @PathVariable(路径变量) : 获取url中的数据
* 属性: value : 路径变量名
* 位置: 放在控制器方法的形参前面
*
*
* {stuId}:定义路径变量, stuId自定义名称
*/
@GetMapping("/student/{stuId}")
public String queryStudent(@PathVariable("stuId") Integer studentId){
return "查询学生studentId="+studentId;
}
/***
* 创建资源 Post请求方式
* http://localhost:8080/myboot/student/zhangsan/20
*/
@PostMapping("/student/{name}/{age}")
public String createStudent(@PathVariable("name") String name,
@PathVariable("age") Integer age){
return "创建资源 student: name="+name+"#age="+age;
}
/**
* 更新资源
*
* 当路径变量名称和 形参名一样, @PathVariable中的value可以省略
*/
@PutMapping("/student/{id}/{age}")
public String modifyStudent(@PathVariable Integer id,
@PathVariable Integer age){
return "更新资源, 执行put请求方式: id="+id+"#age="+age;
}
/**
* 删除资源
*/
@DeleteMapping("/student/{id}")
public String removeStudentById(@PathVariable Integer id){
return "删除资源,执行delete, id="+id;
}
}
3、Postman : 测试工具
- 使用Postman : 可以测试 get ,post , put ,delete 等请求
4、在页面中或者ajax中,支持put,delete请求
-
在SpringMVC中 有一个过滤器, 支持post请求转为put ,delete
-
过滤器:org.springframework.web.filter.HiddenHttpMethodFilter
-
作用:把请求中的post请求转为 put , delete
-
实现步骤:
- application.properties(yml) : 开启使用 HiddenHttpMethodFilter 过滤器
server.port=9001 server.servlet.context-path=/myredis #启用支持put,delete spring.redis.host=localhost spring.redis.port=6379 #spring.redis.password=123
- 在请求页面中,包含 _method参数, 他的值是 put, delete ,发起这个请求使用的post方式
<form action="student/test" method="post"> <input type="hidden" name="_method" value="put"> <input type="submit" value="测试请求方式"> </form>
六、SpringBoot集成Redis
- Spring,SpringBoot中有 一个RedisTemplate(StringRedisTemplate),处理和redis交互
- RedisTemplate 使用的 lettuce 客户端库
- 在程序中使用RedisTemplate类的方法 操作redis数据, 实际就是调用的lettuce 客户端的中的方法
1、配置Windows版本的redis
- Redis-x64-3.2.100.rar 解压缩到一个非中文的目录
- redis-server.exe:服务端, 启动后,不要关闭
- redis-cli.exe:客户端, 访问redis中的数据
- redisclient-win32.x86_64.2.0.jar : Redis图形界面客户端
- 执行方式: 在这个文件所在的目录, 执行 java -jar redisclient-win32.x86_64.2.0.jar
2、使用
-
需求:完善根据学生 id 查询学生的功能,先从 redis 缓存中查找,如果找不到,再从数据库中查找,然后放到 redis 缓存中
-
步骤:
- 依赖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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cooler</groupId> <artifactId>021-springboot-redis</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--redis起步依赖: 直接在项目中使用RedisTemplate(StringRedisTemplate)--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- application.properties
server.port=9001 server.servlet.context-path=/myredis #指定Redis spring.redis.host=localhost spring.redis.port=6379 #spring.redis.password=123
- controller
@RestController public class RedisController { /** * 注入RedisTemplate * * RedisTemplate 泛型 * RedisTemplate<String,String> * RedisTemplate<Object,Object> * RedisTemplate * * 注意: RedisTemplate对象的名称 redisTemplate */ @Resource private RedisTemplate redisTemplate; @Resource private StringRedisTemplate stringRedisTemplate; // 添加数据到redis @PostMapping("/redis/addstring") public String addToRedis(String name, String value){ // 操作Redis中string类型的数据, 先获取ValueOperations对象 ValueOperations valueOperations = redisTemplate.opsForValue(); //添加数据到redis valueOperations.set("myname","lisi"); return "向redis添加string类型的数据"; } // 从redis获取数据 @GetMapping("/redis/getk") public String getData(String k){ ValueOperations valueOperations = redisTemplate.opsForValue(); Object v = valueOperations.get(k); return "key是"+k+",他的值是:"+v; } @PostMapping("/redis/{k}/{v}") public String addStringKV(@PathVariable String k, @PathVariable String v){ // 使用StringRedisTemplate对象 stringRedisTemplate.opsForValue().set(k,v); return "使用StringRedisTemplate对象"; } @GetMapping("/redis/getstr/{k}") public String getStringValue(@PathVariable String k){ String v = stringRedisTemplate.opsForValue().get(k); return "k的value:"+v; } /** 设置 RedisTemplate 序列化 * 可以设置 key 的序列化, 可以设置value的序列化 * 可以同时设置 key 和 value的序列化 */ @PostMapping("/redis/addstr") public String addString(String k,String v){ // 使用RedisTemplate // 设置 key 使用String的序列化 redisTemplate.setKeySerializer( new StringRedisSerializer()); // 设置 value 的序列化 redisTemplate.setValueSerializer( new StringRedisSerializer()); redisTemplate.opsForValue().set(k,v); return "定义RedisTemplate对象的key,value的序列化"; } /** * 使用json 序列化, 把java对象转为json存储 */ @PostMapping("/redis/addjson") public String addJson(){ Student student = new Student(); student.setId(1001); student.setName("zhangsan"); student.setAge(20); redisTemplate.setKeySerializer(new StringRedisSerializer()); // 把值作为json序列化 redisTemplate.setValueSerializer( new Jackson2JsonRedisSerializer(Student.class) ); redisTemplate.opsForValue().set("mystudent", student); return "json序列化"; } @PostMapping("/redis/getjson") public String getJson(){ redisTemplate.setKeySerializer(new StringRedisSerializer()); // 把值作为json序列化 redisTemplate.setValueSerializer( new Jackson2JsonRedisSerializer(Student.class) ); Object obj = redisTemplate.opsForValue().get("mystudent"); return "json反序列化="+ obj; } }
3、对比 StringRedisTemplate 和 RedisTemplate
- StringRedisTemplate:把k,v 都是作为String处理,使用的是String的序列化 ,可读性好。
- RedisTemplate:把k,v 经过了序列化存到redis。k,v 是序列化的内容,不能直接识别。默认使用的jdk序列化,可以修改为前提的序列化
- 序列化:把对象转化为可传输的字节序列过程称为序列化。
- 反序列化:把字节序列还原为对象的过程称为反序列化。
- 为什么需要序列化:
- 序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。而进行跨平台存储和网络传输的方式就是IO,IO支持的数据格式就是字节数组。必须在把对象转成字节数组的时候就制定一种规则(序列化),那么从IO流里面读出数据的时候再以这种规则把对象还原回来(反序列化)。
- 什么情况下需要序列化:
- 凡是需要进行“跨平台存储”和”网络传输”的数据,都需要进行序列化。本质上存储和网络传输 都需要经过 把一个对象状态保存成一种跨平台识别的字节格式,然后其他的平台才可以通过字节信息解析还原对象信息。
- 序列化的方式:
- 序列化只是一种拆装组装对象的规则,那么这种规则肯定也可能有多种多样,比如现在常见的序列化方式有:JDK(不支持跨语言)、JSON、XML、Hessian、Kryo(不支持跨语言)、Thrift、Protofbuff、
java的序列化: 把java对象转为byte[], 二进制数据
json序列化:json序列化功能将对象转换为 JSON 格式或从 JSON 格式转换对象。
例如把一个Student对象转换为JSON字符串{"name":"李四", "age":29} )
反序列化(将JSON字符串 {"name":"李四", "age":29} 转换为Student对象)
七、SpringBoot集成Dubbo
- 阿里巴巴提供了 dubbo 集成 springBoot 开源项目,可以到 GitHub 上 https://github.com/apache/dubbo-spring-boot-project 查看入门教程
使用
(1)接口项目,公共项目(一个普通的maven项目)
- model——Student
public class Student implements Serializable {
private static final long serialVersionUID = 1901229007746699151L;
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;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 接口service——StudentService
public interface StudentService {
Student queryStudent(Integer id);
}
(2)提供者模块(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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cooler</groupId>
<artifactId>023-service-provider</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--加入公共项目的gav-->
<dependency>
<groupId>com.cooler</groupId>
<artifactId>022-interface-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--dubbo依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!--zookeeper依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.8</version>
<type>pom</type>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 实现接口Service——impl——StudentServiceImpl
/**
* 使用dubbo中的注解暴露服务
*/
//@Component 可以不用加
@DubboService(interfaceClass = StudentService.class,version = "1.0",timeout = 5000)
public class StudentServiceImpl implements StudentService {
@Override
public Student queryStudent(Integer id) {
Student student = new Student();
if( 1001 == id){
student.setId(1001);
student.setName("------1001-张三");
student.setAge(20);
} else if(1002 == id){
student.setId(1002);
student.setName("#######1002-李四");
student.setAge(22);
}
return student;
}
}
- application.properties
#配置服务名称 dubbo:application name="名称"
spring.application.name=studentservice-provider
#配置扫描的包
dubbo.scan.base-packages=com.cooler.service
#dubbo的协议和端口号
#dubbo.protocol.name=dubbo
#dubbo.protocol.port=20881
#注册中心
dubbo.registry.address=zookeeper://localhost:2181
- 启动类——ProviderApplication
/**
* @EnableDubbo 启用Dubbo 包含以下两个内容
* @EnableDubboConfig
* @DubboComponentScan
*/
@SpringBootApplication
//@EnableDubboConfig
@EnableDubbo
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
(3)消费者模块
- 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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cooler</groupId>
<artifactId>024-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--加入公共项目的gav-->
<dependency>
<groupId>com.cooler</groupId>
<artifactId>022-interface-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--dubbo依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!--zookeeper依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.8</version>
<type>pom</type>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- Controller
@RestController
public class DubboController {
/**
* 引用远程服务, 把创建好的代理对象,注入给studentService
*/
//@DubboReference(interfaceClass = StudentService.class,version = "1.0")
/**
* 没有使用interfaceClass,默认的就是 引用类型的 数据类型
*/
@DubboReference(version = "1.0")
private StudentService studentService;
@GetMapping("/query")
public String queryStudent(Integer id){
Student student = studentService.queryStudent(id);
return "调用远程接口,获取对象:"+student;
}
}
- ConsumerApplication
@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
- application.properties
#指定服务名称
spring.application.name=consumer-application
#指定注册中心
dubbo.registry.address=zookeeper://localhost:2181
#指定扫描的包
dubbo.scan.base-packages=com.cooler.controller
八、Spring Boot 打包
- Spring Boot 可以打包为 war 或 jar 文件。 以两种方式发布应用
1、打包成war
- 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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cooler</groupId>
<artifactId>025-springboot-war</artifactId>
<version>1.0.0</version>
<!--打包类型-->
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--加入处理jsp的依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<!--打包后的文件名称-->
<finalName>myboot</finalName>
<!--resources插件, 把jsp编译到指定的目录-->
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<!--使用了mybatis ,而且mapper文件放在src/main/java目录-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<!--把src/main/resources下面的所有文件,都包含到classes目录-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- application,properties
server.port=9001
server.servlet.context-path=/myjsp
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
- 主启动类
/**
* SpringBootServletInitializer: 继承这个类, 才能使用独立tomcat服务器
*/
@SpringBootApplication
public class JspApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(JspApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(JspApplication.class);
}
}
2、打包成jar
- 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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cooler</groupId>
<artifactId>026-springboot-jar</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--tomcat依赖,处理jsp-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<!--打包后的文件名称-->
<finalName>myboot</finalName>
<!--加入resources插件 -->
<!--指定编译jsp到META-INF/resources-->
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<!--如果使用mybatis,同时把xml文件放在了src/main/java目录-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<!--把src/main/resources中的所有文件编译到classpath目录中-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--打包jar, 有jsp文件时,必须指定maven-plugin插件的版本是 1.4.2.RELEASE-->
<version>1.4.2.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
- controller
//之前使用的是@RestController,是因为本次操作有视图,不单单只有数据
@Controller
public class HelloController {
@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView mv = new ModelAndView();
mv.addObject("data","SpringBoot打包为jar");
mv.setViewName("main");
return mv;
}
}
-
可以在该jar包所在的目录下cmd,使用java -jar 该文件的名字.jar可以独立启动。(使用的是springboot内嵌的Tomcat)
-
部署到Linux中
- 在任意位置创建一个文件,比如run.sh(和xxx.jar在同一个目录)
- 在文件内部写入:
#!/bin/sh java -jar xxx.jar //如果不在同一目录,需写成java -jar /usr/xxx/xxx/xx.jar
- 赋予权限:chmod 777.run.sh
- 执行脚本文件:./run.sh
3、区别
- war:服务器占用资源比较多,但是能够充分利用服务器的能力
- jar:轻巧简单,内嵌的服务器性能比不上使用独立的服务器。
九、Thymeleaf模板
1、认识Thymeleaf
- Thymeleaf:是使用java开发的模板技术,在服务器端运行。把处理后的数据发送给浏览器。
- 模板是作视图层工作的,显示数据的。Thymeleaf是基于Html语言。
- Thymleaf语法是应用在html标签中 。SpringBoot框架集成Thymealeaf, 使用Thymeleaf代替jsp。
2、运用Thymeleaf的第一个例子
- controller
@Controller
public class HelloThymeleafController {
@GetMapping("/hello")
public String helloThymeleaf(Model model,HttpServletRequest request){
//添加数据到request作用域, 模板引擎可以从request中获取数据
request.setAttribute("data","欢迎使用Thymeleaf模板引擎");
//使用model存放对象
model.addAttribute("mydata","model中的数据");
//指定视图(模板引用使用的页面(html))
//逻辑名称 classpath:/templates/hello.html
return "hello";
}
}
- resources——templates——hello.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>hello.html</title>
</head>
<body>
<h3>使用Thymeleaf的例子</h3>
<p th:text="${data}">
显示数据:
</p>
<p th:text="${mydata}">
显示数据:
</p>
</body>
</html>
- 没有经过服务器时,即没有使用Thymeleaf模板时,直接显示的是“显示数据”,使用了之后,该文字不再显示,显示的是request中所存的数据“data"——“欢迎使用Thymeleaf模板引擎”
- 模板引擎的常用设置
#在开发阶段,关闭模板引擎,让修改立即生效
spring.thymeleaf.cache=false
#编码格式
spring.thymeleaf.encoding=utf-8
#模板类型(默认是HTML)
spring.thymeleaf.mode=HTML
#模板的前缀
spring.thymeleaf.prefix=classpath:/templates/
#模板后缀
spring.thymeleaf.suffix=.html
3、表达式
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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cooler</groupId>
<artifactId>028-thymeleaf-course</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--模板起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(1)标准变量表达式
- 语法: ${key}
- 作用: 获取key对于的文本数据, key 是request作用域中的key , 使用request.setAttribute(), model.addAttribute()
- 在页面中的 html标签中, 使用 th:text=“${key}”
<div style="margin-left: 400px">
<h3>标准变量表达式: ${key}</h3>
<p th:text="${site}">key不存在</p>
<br/>
<p>获取SysUser对象 属性值</p>
<p th:text="${myuser.id}">id</p>
<p th:text="${myuser.name}">姓名</p>
<p th:text="${myuser.sex}">性别:m男</p>
<p th:text="${myuser.age}">年龄</p>
<p th:text="${myuser.getName()}">获取姓名使用getXXX</p>
</div>
(2)选择变量表达式( 星号变量表达式)
- 语法: *{key}
- 作用: 获取这个key对应的数据, *{key}需要和th:object 这个属性一起使用。目的是简单获取对象的属性值。
<p>使用 *{} 获取SysUser的属性值</p>
<div th:object="${myuser}">
<p th:text="*{id}"></p>
<p th:text="*{name}"></p>
<p th:text="*{sex}"></p>
<p th:text="*{age}"></p>
</div>
<p>使用*{}完成的表示 对象的属性值</p>
<p th:text="*{myuser.name}" ></p>
(3)链接表达式
-
语法: @{url}
-
作用: 表示链接, 可以如下
<script src="..."> ,
<link href="...">
<a href=".."> ,
<form action="...">
<img src="...">
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>链接表达式</title>
</head>
<body>
<h3>链接绝对路径</h3>
<a th:href="@{http://www.baidu.com}">链接到百度</a>
<h3>链接的是相对地址</h3>
<a th:href="@{/tpl/queryAccount}">相对地址,没有参数</a>
<h3>链接的相对地址,使用字符串链接传递参数</h3>
<a th:href="@{'/tpl/queryAccount?id='+ ${userId} }">获取model中数据</a>
<h3>推荐使用的传参数的方式</h3>
<a th:href="@{/tpl/queryAccount(id=${userId})}">传参数</a>
<h3>传递多个参数</h3>
<a th:href="@{/tpl/queryUser(name='lisi',age=20)}">传多个参数</a>
</body>
</html>
4、Thymeleaf属性
- 属性是放在html元素中的,就是html元素的属性,加入了th前缀,属性的作用不变。加上th, 属性的值由模板引擎处理。 在属性可以使用变量表达式。例如:
<form action="/loginServlet" method="post"></form>
<form th:action="/loginServlet" th:method="${methodAttr}"></form>
(1)简单
<form id="login" th:action="@{/login}" th:method="post">......</form>
<form id="login" th:action="@{/login}" th:method="post">......</form>
<a th:href="@{/query/student}">相对地址没有传参数</a>
<script type="text/javascript" th:src="@{/js/jquery-3.4.1.js}"></script>
<input type="text" id="realName" name="reaName" th:text="${realName}">
<a th:onclick="'fun1('+${user.id}+')'" th:style="'color:red'">点击我</a>
- 实例:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>属性</title>
<script th:src="@{/js/jquery-3.4.1.js}" type="text/javascript"></script>
</head>
<body>
<div style="margin-left: 400px">
<h3>属性使用, 在html元素的属性上加入th</h3>
<form th:action="@{/loginServlet}" th:method="${methodAttr}">
<input th:type="text" th:name="${paramname}" th:value="${uservalue}"> <br/>
<input type="button" id="btn" th:onclick="btnClick()" value="按钮">
</form>
<p th:style="${textcolor}">这是模板的例子</p>
</div>
</body>
<script type="text/javascript">
function btnClick(){
alert("按钮单击了");
}
$(function(){
$("#btn").click(function(){
alert("click===jquery")
})
})
</script>
</html>
(2)th:each
- each循环, 可以循环List,Array
- 语法:在一个html标签中,使用th:each
<div th:each="集合循环成员,循环的状态变量:${key}">
<p th:text="${集合循环成员}" ></p>
</div>
集合循环成员,循环的状态变量:两个名称都是自定义的。
“循环的状态变量”这个名称可以不定义,默认是"集合循环成员Stat"
th:each="user, iterStat : ${userlist}"中:
◼ iterStat
${userList} 循环体的信息,通过该变量可以获取如下信息:
index: 当前迭代对象的 index(从 0 开始计算)
count: 当前迭代对象的个数(从 1 开始计算)这两个用的较多
size: 被迭代对象的大小
current: 当前迭代变量
even/odd: 布尔值,当前循环是否是偶数/奇数(从 0 开始计算)
first: 布尔值,当前循环是否是第一个
last: 布尔值,当前循环是否是最后一个
注意:循环体信息 iterStat 也可以不定义,则默认采用迭代变量加上 Stat 后缀,即userStat
①循环List
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>each循环</title>
</head>
<body>
<div style="margin-left: 400px">
<!--<div th:each="user,userIter:${myusers}">
<p th:text="${user.id}"></p>
<p th:text="${user.name}"></p>
<p th:text="${user.sex}"></p>
<p th:text="${user.age}"></p>
</div>-->
<br/>
<br/>
<table border="1" cellpadding="0" cellspacing="0">
<thead>
<tr>
<td> 编号</td>
<td> id 序号 </td>
<td> name </td>
<td> sex </td>
<td> age </td>
<td>姓名</td>
<td>是否是第一行</td>
</tr>
</thead>
<tbody>
<tr th:each="user:${myusers}">
<td th:text="${userStat.count}+'/'+${userStat.size}"></td>
<td th:text="${user.id}"></td>
<td th:text="${user.name}"></td>
<td th:text="${user.sex}"></td>
<td th:text="${user.age}"></td>
<td th:text="${userStat.current.name}"></td>
<td th:text="${userStat.first}"/>
</tr>
</tbody>
</table>
</div>
</body>
</html>
②循环Array
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>each循环</title>
</head>
<body>
<div style="margin-left: 400px">
<div th:each="user:${userarray}">
<p th:text="${user.id}"></p>
<p th:text="${user.name}"></p>
<p th:text="${user.sex}"></p>
<p th:text="${user.age}"></p>
<br/>
<hr/>
</div>
</div>
</body>
</html>
和循环List一样
③each循环Map
<div th:each="集合循环成员,循环的状态变量:${key}">
<p th:text="${集合循环成员.key}" ></p>
<p th:text="${集合循环成员.value}" ></p>
</div>
集合循环成员,循环的状态变量:两个名称都是自定义的。 “循环的状态变量”这个名称可以不定义,默认是"集合循环成员Stat"
key:map集合中的key
value:map集合key对应的value值
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>循环Map</title>
</head>
<body>
<div style="margin-left: 400px">
<div th:each="map,userStat:${mymap}">
<p th:text="${map.key}"></p>
<p th:text="${map.value}" ></p>
<p th:text="${map.value.id}"></p>
<p th:text="${map.value.name}"></p>
<p th:text="${userStat.index}"></p>
<br/>
<hr/>
</div>
<br/>
<br/>
</div>
</body>
</html>
④List<Map<String,user>>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>循环Map</title>
</head>
<body>
<div style="margin-left: 400px">
<h3>循环List《Map》 Map<String,SysUser> lm: listmap.get(0)</h3>
<div th:each="lm:${listmap}">
<!--循环map中的所有key,value-->
<div th:each="m:${lm}">
<p th:text="${m.key}"></p>
<p th:text="${m.value.id}"></p>
<p th:text="${m.value.name}"></p>
<p th:text="${m.value.age}"></p>
<br/>
<hr/>
</div>
<br>
<hr>
</div>
</div>
</body>
</html>
(3)条件判断if
- “th:if” : 判断语句, 当条件为true, 显示html标签体内, 反之不显示,没有else语句
语法:
<div th:if=" 10 > 0 "> 显示文本内容 </div>
<div style="margin-left: 400px">
<h3> if 使用</h3>
<p th:if="${sex=='m'}">性别是男</p>
<p th:if="${isLogin}">已经登录系统</p>
<p th:if="${age > 20}">年龄大于20</p>
<!--""空字符是true-->
<p th:if="${name}">name是“”</p>
<!--null是false-->
<p th:if="${isOld}"> isOld是null</p>
</div>
- 还有一个 th:unless 和 th:if相反的行为
语法:
<div th:unless=" 10 < 0 "> 当条件为false显示标签体内容 </div>
<div style="margin-left: 400px">
<h3>unless: 判断条件为false,显示标签体内容</h3>
<p th:unless="${sex=='f'}">性别是男的</p>
<p th:unless="${isLogin}">登录系统</p>
<p th:unless="${isOld}"> isOld是null </p>
</div>
(4)switch,case判断语句
- th:switch 和 java中的switch一样的
语法:
<div th:switch="要比对的值">
<p th:case="值1">
结果1
</p>
<p th:case="值2">
结果2
</p>
<p th:case="*">
默认结果
</p>
以上的case只有一个语句执行
</div>
(5)th:inline
- th:inline 有三个取值类型 (text, javascript 和 none)
①内联text: 在html标签外,获取表达式的值
- 可以让 Thymeleaf 表达式不依赖于 html 标签,直接使用内联表达式[[表达式]]即可获取动态数据
- 要求在父级标签上加 th:inline = “text”属性
- 语法:
<p>显示姓名是:[[${key}]]</p>
<div style="margin-left: 400px">
<h3>内联 text, 使用内联表达式显示变量的值</h3>
<div th:inline="text">
<p>我是[[${name}]],年龄是[[${age}]]</p>
我是<span th:text="${name}"></span>,年龄是<span th:text="${age}"></span>
</div>
<div>
<p>使用内联text</p>
<p>我是[[${name}]],性别是[[${sex}]]</p>
</div>
</div>
②内联javascript
- 可以在 js 中,获取模版中的数据。
例子:
<script type="text/javascript" th:inline="javascript">
var myname = [[${name}]];
var myage = [[${age}]];
//alert("获取的模板中数据 "+ myname + ","+myage)
function fun(){
alert("单击事件,获取数据 "+ myname + ","+ [[${sex}]])
}
</script>
5、字面量
<div style="margin-left: 400px">
<h3>文本字面量: 使用单引号括起来的字符串</h3>
<p th:text="'我是'+${name}+',我所在的城市'+${city}">数据显示</p>
<h3>数字字面量</h3>
<p th:if="${20>5}"> 20大于 5</p>
<h3>boolean字面量</h3>
<p th:if="${isLogin == true}">用户已经登录系统</p>
<h3>null字面量</h3>
<p th:if="${myuser != null}">有myuser数据</p>
</div>
6、字符串连接
- 连接字符串有两种语法:
- 语法使用 单引号括起来字符串 ,使用 + 连接其他的字符串或者表达式
<p th:text="'我是'+${name}+',我所在的城市'+${city}">数据显示</p>
- 语法:使用双竖线, |字符串和表达式|
<p th:text="|我是${name},我所在城市${city|">
显示数据
</p>
- 例子
<div style="margin-left: 400px">
<h3>字符串连接方式1:使用单引号括起来的字符串</h3>
<p th:text="'我是'+${name}+',我所在的城市'+${city}">数据显示</p>
<br/>
<br/>
<h3>字符串连接方式2:|字符串和表达式|</h3>
<p th:text="|我是${name},所在城市${city},其他人${myuser.name}|"></p>
</div>
7、运算符
算术运算: + , - - , * , / , %
关系比较: > , < , >= , <= ( gt , lt , ge , le )
相等判断: == , != ( eq , ne )
三元运算符:(三元运算符可以嵌套)
表达式 ? true的结果 : false的结果
<div style="margin-left: 400px">
<h3>使用运算符</h3>
<p th:text="${age > 10}">年龄大于 10 </p>
<p th:text="${ 20 + 30 }">显示运算结果</p>
<p th:if="${myuser == null}">myuser是null</p>
<p th:if="${myuser eq null}">myuser是null</p>
<p th:if="${myuser ne null}">myuser不是null</p>
<p th:text="${isLogin == true ? '用户已经登录' : '用户需要登录'}"></p>
<p th:text="${isLogin == true ? ( age > 10 ? '用户是大于10的' : '用户年龄比较小') : '用户需要登录'}"></p>
</div>
8、基本Thymeleaf对象
-
#request 表示HttpServletRequest
-
#session表示HttpSession对象
-
session对象:表示Map对象的, 是#session的简单表示方式, 用来获取session中指定的key的值
- #session.getAttribute(“loginname”) == session.loginname
//模板内置对象
@GetMapping("/baseObject")
public String baseObject(Model model, HttpServletRequest request,
HttpSession session){
//添加数据
model.addAttribute("myname","李思");
request.setAttribute("requestData","request作用域中的数据");
request.getSession().setAttribute("sessionData","session作用域中的数据");
//直接使用session
session.setAttribute("loginname","zhangsan");
return "baseObject";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>模板内置对象,方便使用request,session</title>
</head>
<body>
<div style="margin-left: 350px">
<h3>内置对象#request,#session,session的使用</h3>
<p>获取作用域中的数据</p>
<p th:text="${#request.getAttribute('requestData')}"></p>
<p th:text="${#session.getAttribute('sessionData')}"></p>
<p th:text="${session.loginname}"></p>
<br/>
<br/>
<h3>使用内置对象的方法</h3>
getRequestURL=<span th:text="${#request.getRequestURL()}"></span><br/>
getRequestURI=<span th:text="${#request.getRequestURI()}"></span><br/>
getQueryString=<span th:text="${#request.getQueryString()}"></span><br/>
getContextPath=<span th:text="${#request.getContextPath()}"></span><br/>
getServerName=<span th:text="${#request.getServerName()}"></span><br/>
getServerPort=<span th:text="${#request.getServerPort()}"></span><br/>
sessionId,getId=<span th:text="${#session.getId()}"></span>
<h3>param对象:表示请求的参数集合</h3>
name参数的值:<span th:text="${param.name}"></span><br/>
参数的数量:<span th:text="${param.size()}"></span><br/>
</div>
</body>
</html>
9、内置工具类
- 内置工具类型: Thymeleaf自己的一些类,提供对string, date ,集合的一些处理方法
- #dates: 处理日器的工具类
- #numbers:处理数字
- #lists: 处理list集合
//内置的工具类对象
@GetMapping("/utilobject")
public String utilObject(Model model){
model.addAttribute("mydate",new Date());
model.addAttribute("mynum",26.695);
model.addAttribute("mystr","cooler");
List<String> list = Arrays.asList("a","b","c");
model.addAttribute("mylist",list);
//创建Zoo对象
Zoo zoo = new Zoo();
Cat cat = new Cat();
cat.setName("短腿");
Dog dog = new Dog();
dog.setName("二哈");
zoo.setCat(cat);
//zoo.setDog(dog); zoo.dog = null
model.addAttribute("zoo",zoo);
return "utilObject";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>内置工具类对象</title>
</head>
<body>
<div style="margin-left: 350px">
<h3>日期类对象 #dates</h3>
<p th:text="${#dates.format(mydate )}"></p>
<p th:text="${#dates.format(mydate,'yyyy-MM-dd')}"></p>
<p th:text="${#dates.format(mydate,'yyyy-MM-dd HH:mm:ss')}"></p>
<p th:text="${#dates.year(mydate)}"></p>
<p th:text="${#dates.month(mydate)}"></p>
<p th:text="${#dates.monthName(mydate)}"></p>
<p th:text="${#dates.createNow()}"></p>
<br/>
<h3>内置工具类#numbers,操作数字的</h3>
<p th:text="${#numbers.formatCurrency(mynum)}"></p>
<p th:text="${#numbers.formatDecimal(mynum,5,2)}"></p>
<br/>
<h3>内置工具类#strings,操作字符串</h3>
<p th:text="${#strings.toUpperCase(mystr)}"></p>
<p th:text="${#strings.indexOf(mystr,'cool')}"></p>
<p th:text="${#strings.substring(mystr,2,5)}"></p>
<p th:text="${#strings.substring(mystr,2)}"></p>
<p th:text="${#strings.concat(mystr,'---A cool man---')}"></p>
<p th:text="${#strings.length(mystr)}"></p>
<p th:text="${#strings.length('hello')}"></p>
<p th:unless="${#strings.isEmpty(mystr)}"> mystring 不是 空字符串 </p>
<br/>
<h3>内置工具类#lists,操作list集合</h3>
<p th:text="${#lists.size(mylist)}"></p>
<p th:if="${#lists.contains(mylist,'a')}">有成员a</p>
<p th:if="!${#lists.isEmpty(mylist)}"> list 集合有多个成员</p>
<br/>
<h3>处理null</h3>
<p th:text="${zoo?.dog?.name}"></p>
</div>
</body>
</html>
10、自定义模板
-
模板是内容复用, 定义一次,在其他的模板文件中多次使用。
-
模板使用:
- 定义模板
th:fragment="模板自定义名称" 例如: <div th:fragment="head"> <p> CoolEr学习Java </p> <p> www.cooler.com </p> </div>
- 使用模板
1) ~{templatename :: selector} templatename: 文件名称 selector: 自定义模板名称 2)templatename :: selector templatename: 文件名称 selector: 自定义模板名称 对于使用模板: 有包含模板(th:include) 插入模板(th:insert)
-
例子:
-
head.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div th:fragment="top">
<p>CoolEr</p>
<p>网站 www.cooler.com</p>
</div>
<div th:fragment="menu">
<p>文档|下载|blog</p>
</div>
</body>
</html>
- foot.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
footer.html
@copy; CoolEr2022
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>使用模板</title>
</head>
<body>
<div style="margin-left: 350px">
<h3>使用其他目录中的模板文件</h3>
<div th:insert="common/left :: html"></div>
<br/>
<br/>
<div th:include="common/left"></div>
<div th:insert="head :: menu"></div>
<h3>插入模板 th:insert</h3>
<div th:insert="~{ head :: top }">
</div>
<br/>
<br/>
<h3>插入模板 第二种格式</h3>
<p th:insert="head :: top"></p>
<br/>
<br/>
<h3>包含模板,第一种语法</h3>
<div th:include="~{ head :: top}">
</div>
<br/>
<br/>
<h3>包含模板,第二种语法</h3>
<div th:include="head :: top">
</div>
<br/>
<br/>
<h3>使用整个文件作为复用的内容(整个文件作为模板使用)</h3>
<div th:include="footer :: html"></div>
<br/>
<div th:include="footer" ></div>
<br/>
<div th:insert="footer"></div>
</div>
</body>
</html>
十、总结
1、创建对象的注解
- @Controller: 放在类的上面,创建控制器对象,注入到容器中
- @RestController: 放在类的上面,创建控制器对象,注入到容器中。
- 作用:复合注解是@Controller , @ResponseBody, 使用这个注解类的,里面的控制器方法的返回值都是数据
- @Service : 放在业务层的实现类上面,创建service对象,注入到容器
- @Repository : 放在dao层的实现类上面,创建dao对象,放入到容器。
- 没有使用这个注解,是因为现在使用MyBatis框架,dao对象是MyBatis通过代理生成的。
- @Component: 放在类的上面,创建此类的对象,放入到容器中。
2、属性赋值
- @Value : 简单类型的赋值
- 例如:在属性的上面使用@Value(“李四”) private String name
- 还可以使用@Value,获取配置文件中的数据(properties或yml)——@Value(“${server.port}”) private Integer port
- @Autowired: 引用类型赋值自动注入的,支持byName, byType,默认是byType 。
- 放在属性的上面,也可以放在构造方法的上面。 推荐是放在构造方法的上面
- @Qualifer: 给引用类型赋值,使用byName方式。
(@Autowird, @Qualifer都是Spring框架提供的。) - @Resource : 来自jdk中的定义, javax.annotation。 实现引用类型的自动注入, 支持byName, byType。默认是byName, 如果byName失败,再使用byType注入。
- 在属性上面使用
3、其他
- @Configuration : 放在类的上面,表示这是个配置类,相当于xml配置文件
- @Bean:放在方法的上面, 把方法的返回值对象,注入到spring容器中。
- @ImportResource : 加载其他的xml配置文件, 把文件中的对象注入到spring容器中
- @PropertySource : 读取其他的properties属性配置文件
- @ComponentScan: 扫描器 ,指定包名,扫描注解的
- @ResponseBody: 放在方法的上面,表示方法的返回值是数据, 不是视图
- @RequestBody : 把请求体中的数据,读取出来, 转为java对象使用。
- @ControllerAdvice: 控制器增强, 放在类的上面, 表示此类提供了方法,可以对controller增强功能。
- @ExceptionHandler : 处理异常的,放在方法的上面
- @Transcational : 处理事务的, 放在service实现类的public方法上面, 表示此方法有事务
4、SpringBoot中使用的注解
- @SpringBootApplication : 放在启动类上面, 包含了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
5、MyBatis相关的注解
- @Mapper : 放在类的上面 , 让MyBatis找到接口, 创建他的代理对象
- @MapperScan :放在主类的上面 , 指定扫描的包, 把这个包中的所有接口都创建代理对象。 对象注入到容器中
- @Param : 放在dao接口的方法的形参前面, 作为命名参数使用的。
6、Dubbo注解
- @DubboService: 在提供者端使用的,暴露服务的, 放在接口的实现类上面
- @DubboReference: 在消费者端使用的, 引用远程服务, 放在属性上面使用。
- @EnableDubbo : 放在主类上面, 表示当前引用启用Dubbo功能。
7、总结
注解 | 解释 |
---|---|
@Controller | 组合注解(组合了@Component注解),应用在MVC层(控制层),DispatcherServlet会自动扫描注解了此注解的类,然后将web请求映射到注解了@RequestMapping的方法上。 |
@Service | 组合注解(组合了@Component注解),应用在service层(业务逻辑层) |
@Reponsitory | 组合注解(组合了@Component注解),应用在dao层(数据访问层) |
@Component | 表示一个带注释的类是一个“组件”,成为Spring管理的Bean。当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时@Component还是一个元注解。 |
@Autowired | Spring提供的工具(由Spring的依赖注入工具(BeanPostProcessor、BeanFactoryPostProcessor)自动注入。) |
@Resource | JSR-250提供的注解 |
@Inject | JSR-330提供的注解 |
@Configuration | 声明当前类是一个配置类(相当于一个Spring配置的xml文件) |
@ComponentScan | 自动扫描指定包下所有使用@Service,@Component,@Controller,@Repository的类并注册 |
@Bean | 注解在方法上,声明当前方法的返回值为一个Bean。返回的Bean对应的类中可以定义init()方法和destroy()方法,然后在@Bean(initMethod=”init”,destroyMethod=”destroy”)定义,在构造之后执行init,在销毁之前执行destroy。 |
@Aspect | 声明一个切面(就是说这是一个额外功能) |
@After | 后置建言(advice),在原方法前执行。 |
@Before | 前置建言(advice),在原方法后执行。 |
@Around | 环绕建言(advice),在原方法执行前执行,在原方法执行后再执行(@Around可以实现其他两种advice) |
@PointCut | 声明切点,即定义拦截规则,确定有哪些方***被切入 |
@Transactional | 声明事务(一般默认配置即可满足要求,当然也可以自定义) |
@Cacheable | 声明数据缓存 |
@EnableAspectJ*** | 开启Spring对AspectJ的支持 |
@Value | 值得注入。经常与Sping EL表达式语言一起使用,注入普通字符,系统属性,表达式运算结果,其他Bean的属性,文件内容,网址请求内容,配置文件属性值等等 |
@PropertySource | 指定文件地址。提供了一种方便的、声明性的机制,用于向Spring的环境添加PropertySource。与@configuration类一起使用。 |
@PostConstruct | 标注在方法上,该方法在构造函数执行完成之后执行。 |
@PreDestroy | 标注在方法上,该方法在对象销毁之前执行。 |
@Profile | 表示当一个或多个指定的文件是活动的时,一个组件是有资格注册的。使用@Profile注解类或者方法,达到在不同情况下选择实例化不同的Bean。@Profile(“dev”)表示为dev时实例化。 |
@EnableAsync | 开启异步任务支持。注解在配置类上。 |
@Async | 注解在方法上标示这是一个异步方法,在类上标示这个类所有的方法都是异步方法。 |
@EnableScheduling | 注解在配置类上,开启对计划任务的支持。 |
@Scheduled | 注解在方法上,声明该方法是计划任务。支持多种类型的计划任务:cron,fixDelay,fixRate |
@Conditional | 根据满足某一特定条件创建特定的Bean |
@Enable* | 通过简单的@Enable来开启一项功能的支持。所有@Enable注解都有一个@Import注解,@Import是用来导入配置类的,这也就意味着这些自动开启的实现其实是导入了一些自动配置的Bean(1.直接导入配置类2.依据条件选择配置类3.动态注册配置类) |
@RunWith | 这个是Junit的注解,springboot集成了junit。一般在测试类里使用:@RunWith(SpringJUnit4ClassRunner.class) — SpringJUnit4ClassRunner在JUnit环境下提供Sprng TestContext Framework的功能 |
@ContextConfiguration | 用来加载配置ApplicationContext,其中classes属性用来加载配置类:@ContextConfiguration(classes = {TestConfig.class(自定义的一个配置类)}) |
@ActiveProfiles | 用来声明活动的profile–@ActiveProfiles(“prod”(这个prod定义在配置类中)) |
@EnableWebMvc | 用在配置类上,开启SpringMvc的Mvc的一些默认配置:如ViewResolver,MessageConverter等。同时在自己定制SpringMvc的相关配置时需要做到两点:1.配置类继承WebMvcConfigurerAdapter类2.就是必须使用这个@EnableWebMvc注解。 |
@RequestMapping | 用来映射web请求(访问路径和参数),处理类和方法的。可以注解在类和方法上,注解在方法上的@RequestMapping路径会继承注解在类上的路径。同时支持Serlvet的request和response作为参数,也支持对request和response的媒体类型进行配置。其中有value(路径),produces(定义返回的媒体类型和字符集),method(指定请求方式)等属性。 |
@ResponseBody | 将返回值放在response体内。返回的是数据而不是页面 |
@RequestBody | 允许request的参数在request体中,而不是在直接链接在地址的后面。此注解放置在参数前。 |
@PathVariable | 放置在参数前,用来接受路径参数。 |
@RestController | 组合注解,组合了@Controller和@ResponseBody,当我们只开发一个和页面交互数据的控制层的时候可以使用此注解。 |
@ControllerAdvice | 用在类上,声明一个控制器建言,它也组合了@Component注解,会自动注册为Spring的Bean。 |
@ExceptionHandler | 用在方法上定义全局处理,通过他的value属性可以过滤拦截的条件:@ExceptionHandler(value=Exception.class)–表示拦截所有的Exception。 |
@ModelAttribute | 将键值对添加到全局,所有注解了@RequestMapping的方法可获得次键值对(就是在请求到达之前,往model里addAttribute一对name-value而已)。 |
@InitBinder | 通过@InitBinder注解定制WebDataBinder(用在方法上,方法有一个WebDataBinder作为参数,用WebDataBinder在方法内定制数据绑定,例如可以忽略request传过来的参数Id等)。 |
@WebAppConfiguration | 一般用在测试上,注解在类上,用来声明加载的ApplicationContext是一个WebApplicationContext。他的属性指定的是Web资源的位置,默认为src/main/webapp,我们可以修改为:@WebAppConfiguration(“src/main/resources”)。 |
@EnableAutoConfiguration | 此注释自动载入应用程序所需的所有Bean——这依赖于Spring Boot在类路径中的查找。该注解组合了@Import注解,@Import注解导入了EnableAutoCofigurationImportSelector类,它使用SpringFactoriesLoader.loaderFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包。而spring.factories里声明了有哪些自动配置。 |
@SpingBootApplication | SpringBoot的核心注解,主要目的是开启自动配置。它也是一个组合注解,主要组合了@Configurer,@EnableAutoConfiguration(核心)和@ComponentScan。可以通过@SpringBootApplication(exclude={想要关闭的自动配置的类名.class})来关闭特定的自动配置。 |
@ImportResource | 虽然Spring提倡零配置,但是还是提供了对xml文件的支持,这个注解就是用来加载xml配置的。例:@ImportResource({“classpath |
@ConfigurationProperties | 将properties属性与一个Bean及其属性相关联,从而实现类型安全的配置。例:@ConfigurationProperties(prefix=”authot”,locations={“classpath |
@ConditionalOnBean | 条件注解。当容器里有指定Bean的条件下。 |
@ConditionalOnClass | 条件注解。当类路径下有指定的类的条件下。 |
@ConditionalOnExpression | 条件注解。基于SpEL表达式作为判断条件。 |
@ConditionalOnJava | 条件注解。基于JVM版本作为判断条件。 |
@ConditionalOnJndi | 条件注解。在JNDI存在的条件下查找指定的位置。 |
@ConditionalOnMissingBean | 条件注解。当容器里没有指定Bean的情况下。 |
@ConditionalOnMissingClass | 条件注解。当类路径下没有指定的类的情况下。 |
@ConditionalOnNotWebApplication | 条件注解。当前项目不是web项目的条件下。 |
@ConditionalOnResource | 条件注解。类路径是否有指定的值。 |
@ConditionalOnSingleCandidate | 条件注解。当指定Bean在容器中只有一个,后者虽然有多个但是指定首选的Bean。 |
@ConditionalOnWebApplication | 条件注解。当前项目是web项目的情况下。 |
@EnableConfigurationProperties | 注解在类上,声明开启属性注入,使用@Autowired注入。例:@EnableConfigurationProperties(HttpEncodingProperties.class)。 |
@AutoConfigureAfter | 在指定的自动配置类之后再配置。例:@AutoConfigureAfter(WebMvcAutoConfiguration.class) |