SpringBoot两天
SpringBoot讲义
什么是SpringBoot?
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
Spring 从4.x版本开始提倡java配置和注解结合使用,慢慢离开xml繁琐的配置,所以要入门SpringBoot,需要从java配置开始。在Spirng Boot和Spring Cloud中,大量使用了注解与JavaConfig。
JavaConfig诞生的原因是什么?
Spring IOC有一个非常核心的概念——Bean。由Spring容器来负责对Bean的实例化,装配和管理。早些时候XML是用来描述Bean最为流行的配置方式。随着Spring的日益发展,由于Spring会把几乎所有的业务类都以Bean的形式配置在XML文件中,造成了大量的XML文件。使用XML来配置Bean失去了编译时的类型安全检查。大量的XML配置使得整个项目变得更加复杂。
当随着JAVA EE 5.0的发布,其中引入了一个非常重要的特性——Annotations(注解)。注解是源代码的标签,这些标签可以在源代码层进行处理或通过编译器把它熔入到class文件中。在JAVA EE 5以后的版本中,注解成为了一个主要的配置选项。Spring使用注释来描述Bean的配置与采用XML相比,因类注解是在一个类源代码中,可以获得类型安全检查的好处。可以良好的支持重构。
JavaConfig就是使用注解来描述Bean配置的组件。JavaConfig 是Spring的一个子项目。
JavaConfig常见的注解有哪些?
@Configuration注解
该注解贴在类上,表示是一个配置类。相当于xml配置
@Bean注解
Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。添加的bean的id为方法名
也可以执行生命周期的回调函数,类似@PostConstruct(初始化方法) 和 @PreDestroy(销毁方法)的方法
@Scope注解
@Scope 注解:用来设置交给spring容器管理的Bean是单例方式,还是多例方式
相当于bean标签中的scope属性
@ComponentScan注解
创建一个配置类,在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的xml <context:component-scan>。
@Import注解
@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
@ImportResource注解
@ImportResource和@Value进行资源文件读取
@PropertySource, @value 注解
Spring框架提供了PropertySource注解,目的是加载指定的属性文件 @Value 可以获取配置文件中的值
@Profile,@ActiveProfile注解
@profile注解是spring提供的一个用来标明当前运行环境的注解。我们正常开发的过程中经常遇到的问题是,开发环境是一套环境,QA测试是一套环境,线上部署又是一套环境。这样从开发到测试再到部署,会对程序中的配置修改多次,尤其是从QA到上线这个环节,让QA的也不敢保证改了哪个配置之后能不能在线上运行。 为了解决上面的问题,我们一般会使用一种方法,就是配置文件,然后通过不同的环境读取不同的配置文件,从而在不同的场景中跑我们的程序。
那么,spring中的@profile注解的作用就体现在这里。在spring使用DI来依赖注入的时候,能够根据当前制定的运行环境来注入相应的bean。最常见的就是使用不同的DataSource了。
JavaConfig配置的应用场景
在IOC中
需求一:把一个Bean交给Spring管理
回顾使用xml配置方式
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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="someBean" class="cn.wolfcode.javaconfig._01_xmlconfig.SomeBean"/>
</beans>
SomeBean:
public class SomeBean {public void print() {System.out.println("print xmlConfig");}
}
XMLConfigTest:
public class XMLConfigTest {@Testpublic void testXMLConfig() throws Exception {// 加载spring的配置文件ApplicationContext ctx =new ClassPathXmlApplicationContext("cn/wolfcode/javaconfig/_01_xmlconfig/applicationContext.xml");// 通过spring容器获取SomeBeanSomeBean someBean = ctx.getBean(SomeBean.class);// 执行print方法someBean.print();}}
使用javaConfig方式
@Configuration :spring的配置标签,打在哪个类上,这个类就表示spring的配置类, 相当于applicationContext.xml文件
@Bean :打在方法上方法返回的实例对象交给spring容器管理,方法的名称就是Bean标签中的id值。
相当于配置文件中bean标签。
如:
<bean id="someBean" class="cn.wolfcode._01xmlconfig.SomeBean" />
ApplicationConfig:
@Configuration
public class ApplicationConfig {@Beanpublic SomeBean someBean(){return new SomeBean();}
}
SomeBean:
public class SomeBean
{public void print(){System.out.println("print JavaConfig");}
}
这里不再是通过xml配置文件获取spring容器对象,而是通过加载配置类。因此应该选用 AnnotationConfigApplicationContext 类,加载配置类的字节码文件。
JavaConfigTest:
public class JavaConfigTest {@Testpublic void testJavaConfig() throws Exception {// 加载配置类ApplicationContext ctx =new AnnotationConfigApplicationContext(ApplicationConfig.class);// 从spring容器中获取SomeBean对象SomeBean someBean = ctx.getBean(SomeBean.class);// 打印someBean.print();}
}
@ComponentScan
使用该注解改良代码。
通过上述的案例,其实我们发现,上面的写法也显得很麻烦。还不如使用配置文件简洁。
在配置类中,通过给方法添加注解@Bean,把该方法的返回值交给spring管理。代码量太大,如果需要交给Spring管理很多Bean的话,我们要写很多个方法,在配置类中。
在javaConfig中,给我们提供一个注解@ComponentScan,可以把需要管理的Bean 贴上注解@Component,然后通过在配置类上面贴注解@ComponentScan来进行扫描贴了注解的Bean,然后把这些Bean交给Spring管理。
@ComponentScan 这个标签也相当于之前在配置文件中的配置的
<context:component-scan base-package="" />
//开启 ioc组件自动扫描功能
注意:@ComponentScan注解也可以通过配置指定扫描哪个包。
如:@ComponentScan("cn.wolfcode")表示扫描“cn.wolfcode”这个包以及它下面的子包,把包中的贴了注解的Bean ,交给spring容器管理。如果不指定包,表示扫描当前包以及下面的子包
改良方案如下:
ApplicationConfig:
@Configuration
@ComponentScan("cn.wolfcode.javaconfig._03_scan")
public class ApplicationConfig {}
JavaConfigTest:
public class JavaConfigTest {@Testpublic void testJavaConfig() throws Exception {// 加载配置类ApplicationContext ctx =new AnnotationConfigApplicationContext(ApplicationConfig.class);// 从spring容器中获取SomeBean对象SomeBean someBean = ctx.getBean(SomeBean.class);// 打印someBean.print();}
}
SomeBean:
@Component
public class SomeBean
{public void print(){System.out.println("print ScanConfig");}
}
@Bean中的一些属性的补充
属性:initMethod
该属性相当于bean标签中的initMethod属性,用来设置bean被初始化所调用的方法。
如:
<bean id="someBean" class="" init-method="init" />
属性:destroyMethod
该属性相当于bean标签中的destroyMethod 属性,用来设置bean被销毁时,执行的操作。
如:
<bean id="someBean" class="" destroy-method="" />
注意:必须是容器正常关闭,销毁bean,才会调用销毁方法。
使用普通的junit测试,是不能关闭spring容器的。原因是,junit测试方法执行完毕,进程就结束了。所以导致spring容器不能正常关闭。
正常关闭容器的方案:
方案一: 容器使用完手动调用close方法,进行关闭。
如:
//获取容器
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class)
// 关闭容器
ctx.close();
方案二:使用java1.7的新特性try(),来进行关闭。
如:
try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class)) {SomeBean someBean = ctx.getBean(SomeBean.class);System.out.println(someBean);
} catch (Exception e) {e.printStackTrace();
}
方案三:使用Spring整合的junit单元测试。
如:
在测试类上面添加整合单元测试的注解.
注意:因为不再是加载配置文件的方式,所以需要使用classes属性加载配置类信息。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
@Scope注解
@Scope 该注解贴方法上表示是多例还是单例, 相当于配置文件中bean标签的属性scope 的作用。
@Scope("prototype") 表示多例
@Scope("singleton") 表示单例,如果配置@Scope标签,其默认值也是单例。
一般开发中中使用的是单例。
在DI中
需求二:把一个Bean注入给另外一个Bean中
方式一:直接调用方法的形式
@Beanpublic SomeBean someBean() {SomeBean someBean = new SomeBean();System.out.println("someBean create");someBean.setOtherBean(otherBean());return someBean;}@Beanpublic OtherBean otherBean() {OtherBean otherBean = new OtherBean();System.out.println("otherBean create");return otherBean;}
方式二:使用传参的形式
@Bean
public SomeBean someBean(OtherBean otherBean){someBean.setOtherBean(otherBean);return someBean;
}@Bean
public OtherBean otherBean(){return new OtherBean();
}
注意:
@Bean标签的生命周期
在一个@Configuration类中,重复调用一个方法,得到的对象默认也是singleton的
配置类/文件的导入
为何需要导入配置类/配置文件?
在我们实际开发中,项目很大的情况下,采用JavaConfig配置类的方式,为了便于开发和管理,我们的配置类也会有很多个。那么多个配置类之间,只有一个主配置类,这时就需要,把其他的配置类或者配置文件导入到主配置类上面。所以我们需要导入配置类或者配置文件。
导入配置类/配置文件需要哪些注解?
@Import注解
比如一个场景:我们之前项目中可以有多个 配置文件,那么在javaConfig中,也可能存在多个配置类,那么在很多个配置类的情况下,应该有一个主配置类,其他的配置都关联到主配置类上面,那么问题是怎么关联其他配置类呢? 使用@Import注解
@ImportResource注解
比如一个场景:有时候根据项目的需求和对项目的设计,我们可能需要配置类和配置文件混用的情况。例如,使用spring的AOP帮我们处理事务。可能使用javaConfig的方式,比较繁琐,修改代码太过于频繁,那么这块我们就可以继续使用xml文件的方式统一处理。那么这种情形就需要,在主配置类中关联配置文件了。
@Import注解的用法:
导入普通类
例子如下:
-
- 新建一个TestA
public class TestA {public void fun(String str) {System.out.println(str);
}
public void printName() {System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());}
}
-
- 新建一个ImportConfig,在类上面加上@Configuration,加上@Configuration是为了能让Spring 扫描到这个类,并且直接通过@Import引入TestA类
@Import({TestA.class})
@Configuration
public class ImportConfig {
}
导入带有@Configuration的配置类
-
- 新建TestB
@Configuration
public class TestB {public void fun(String str) {System.out.println(str);}public void printName() {System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());}
}
-
- 在ImportConfig.class里面直接引入TestB
@Import({TestA.class,TestB.class})
@Configuration
public class ImportConfig {
}
通过ImportSelector 方式导入的类
-
- 新建TestC.class
public class TestC {public void fun(String str) {System.out.println(str);}public void printName() {System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());}
}
-
- 新建SelfImportSelector.class 实现ImportSelector 接口,注入TestC.class
public class SelfImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.test.importdemo.TestC"};}
}
-
- ImportConfig上面引入SelfImportSelector.class
@Import({TestA.class,TestB.class,SelfImportSelector.class})
@Configuration
public class ImportConfig {}
通过 ImportBeanDefinitionRegistrar 方式导入的类
-
- 新建TestD.class
public class TestD {public void fun(String str) {System.out.println(str);} public void printName() {System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());}
}
-
- 新建SelfImportBeanDefinitionRegistrar.class,实现接口ImportBeanDefinitionRegistrar,注入TestD.class
public class SelfImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {RootBeanDefinition root = new RootBeanDefinition(TestD.class);registry.registerBeanDefinition("testD", root);}
}
-
- ImportConfig类上加上导入SelfImportBeanDefinitionRegistrar.class
@Import({TestA.class,TestB.class,SelfImportSelector.class,SelfImportBeanDefinitionRegistrar.class})
@Configuration
public class ImportConfig {
}
@ImportResource注解的用法:
有时候根据项目的需求和对项目的设计,我们可能需要配置类和配置文件混用的情况。
比如,使用spring的AOP帮我们处理事务。可能使用javaConfig的方式,比较繁琐,修改代码太过于频繁,那么这块我们就可以继续使用xml文件的方式统一处理。那么这种情形就需要,在主配置类中关联配置文件了。
使用@ImportResource注解
是引入spring配置文件.xml,实现xml配置的装载;
通过locations属性或者value属性,加载对应的xml配置文件,同时需要配合@Configuration注解一起使用,定义为配置类;引入的配置类必须在启动类中扫描到.
例子如下:
ApplicationConfig:
@Configuration
@ImportResource("classpath:cn/wolfcode/javaconfig/_07_import_resource/applicationContext.xml")
public class ApplicationConfig {@Beanpublic SomeBean someBean(){return new SomeBean();}
}
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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="cn.wolfcode.javaconfig._07_import_resource.OtherBean"/>
</beans>
ImportResourceConfigTest:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class ImportResourceConfigTest {@Autowiredprivate SomeBean someBean;@Autowiredprivate OtherBean otherBean;@Testpublic void testImportResource() throws Exception {System.out.println("someBean = " + someBean);System.out.println("otherBean = " + otherBean);}
}
资源文件的导入
为何需要导入资源文件?
Spring Boot 官网使用的是application.properties文件来实现文件的配置。但是实际情况下一个配置文件是不够用的,比如项目集成redis,mq,以及数据库比如mysql的时候,多个配置文件有利于开发及维护的管理。
导入资源文件需要学习哪些注解?
@PropertySource注解
大多数情况,项目需要配置的内容会比较复杂,这时候需要使用多个文件进行配置
@PropertySource是Spring boot为了方便引入properties配置文件提供的一个注解,可以标注在SpringBoot的启动类上,还可以标注在配置类(使用@Configuration标注的类)上。
@Value注解
@Value用于将外部的值动态地注入Bean中,相当于使用.xml中的如下的代码。通常用于对某个值进行单个的注入,毕竟如果对整个Bean内的值进行注入我们有更好用的@ConfigurtionProperties可以使用。
@ConfigurtionProperties注解
@Value通常用于对某个位置获取配置文件中的的某一个变量的时候,而@ConfigurationProperties用于javaBean和配置文件进行整体映射。上述的使用场景只是说通常情况,具体的使用,还是要根据@Value和@ConfigurationProperties各自的特点来进行判断。
@Value主要作用到变量上,而@ConfigurationProperties,主要用于方法。
@PropertySource注解的用法:
加载指定的属性文件;
注解的属性value,是一个String数组,内容为一个或多个xml/properties文件的路径(相对于classpath);
注解内部的属性使用,配合@value注解.
properties属性文件是key-value格式的,因此使用起来 是采用@value("${key}"); 这种形式
如:
@Configuration
@PropertySource(value = "classpath:db.properties",
ignoreResourceNotFound = false ,
encoding = "utf-8")
public class ApplicationConfig {
}
属性value
value值是设置需要加载的属性文件,可以一次性加载多个。
属性encoding
encoding用于指定读取属性文件所使用的编码,我们通常使用的是UTF-8;
属性ignoreResourceNotFound
ignoreResourceNotFound含义是当指定的配置文件不存在是否报错,默认是false;实际项目开发中,最好设置为false。
Environment对象的使用
回想mybaits配置文件中的 Environment ,表示mybatis的当前环境
Environment :代表了spring的当前环境,在该环境中只有两个东西
1,外部读入的资源文件 :如通过PropertySource 引入的资源文件2,还有一个东西叫 profile
那么在javaconfig中如何使用 Environment 实现资源文件的注入呢 ?
@Autowired
private Environment evn;@Configuration
//@PropertySource:把资源文件导入到Spring当前环境
@PropertySource("classpath:jdbc.properties")
public class ApplicationConfig
{
// Environment spring的环境对象,其中有两个东西:① propertis ② profile@Bean
public MyDataSource myDataSource(Environment environment){return new MyDataSource(environment.getProperty("jdbc.username"),environment.getProperty("jdbc.password"),environment.getProperty("jdbc.driverClassName"),environment.getProperty("jdbc.url"));}
}
@Value注解的用法:
我们可以点进去看一下@Value的源码,如下,我们发现它其中只包括一个String类型的变量,也就是说我们@Value注解后面只能接一个String类型的变量,无论什么内容都必须包括在双引号之下。
可注入类型:
-
- 字面量:包括布尔、数值型、字符串
- a. 字符串
@Value("字符串内容")
适用于一般的自变量、数组、文件资源和URL资源,Spring Boot会根据配置的变量类型对字符串内容进行转换。
例如:
@Value("true")
private Boolean blog;
- b. SpEL
@Value("#{SpEL内容}")。
通常SpEL内的字符串使用单引号''括起来。适用于需要计算的自变量、特殊数组、键值对、其他bean属性等。
例如:@Value("#{12*15}")
private Integer clickNum;
- c. 注入配置文件中的数据
@Configuration
@PropertySource("classpath:jdbc.properties")
public class ApplicationConfig
{//取资源文件中的内容,对于的值设置到该字段上@Value("${jdbc.username}")private String username;@Value("${jdbc.driverClassName}")private String driverClassName;@Value("${jdbc.url}")private String url;@Value("${jdbc.password}")private String password;@Beanpublic MyDataSource myDataSource(){return new MyDataSource(username,password,driverClassName,url);
}
注意:
如果spring的jar版本过低,必须配置PropertySourcesPlaceholderConfigurer
PropertySourcesPlaceholderConfigurer ,完成资源文件属性到对象参数的绑定,从spring环境对象中拿到资源文件配置,完成对 {key} 表达式的替换
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){return new PropertySourcesPlaceholderConfigurer();}
}
PropertySourcesPlaceholderConfigurer 类最终实现了一个 BeanFactoryPostProcessor 接口 ,他的作用是在BeanFactory创建每一个bean的过程当中加入一些自己的业务逻辑
而实现了BeanFactoryPostProcessor 接口的bean 会在其他所有bean 初始化之前去做一些事情 , 而 PropertySourcesPlaceholderConfigurer 就是在其他所有的bean初始化之前去寻找是否有 value 标签, 如果有完成属性的替换, 所以我们得需要保证 PropertySourcesPlaceholderConfigurer 在其他所有类之前被创建,所以需要在 该bean的定义方法是 static
-
- 数组(List)
字符串:与字面量类似,字符串之间使用英文的“,”隔开。
如:
@Value("Spring Boot, IDEA")
private List<String> key;
SpEL:比如我们需要字符串中有逗号的时候,使用SpEL就会更合适一些。
如:
@Value("#{'Spring Boot;IDEA'.split(';')}")
private List<String> key;
-
- 键值对(Map)
对于键值对我们不能直接使用字符串,可以使用SpEL,也可以配合配置文件来进行使用。
a. SpEL,注意第二层的括号一定要有:
@Value("#{{color:'red', language:'Chinese'}}")
private Map<String,String> otherProperties;
b. 如果结合配置文件使用,我们这里使用.properties格式和.yml格式的配置的方式有些不同,先来看.properties配置文件代码:
valuesMap={color:'red', language:'Chinese'}代码中获取:@Value("#{${valuesMap}}")private Map<String,String> otherProperties;
如果配置文件使用yml,需要注意。
yml在进行单行键值对赋值的时候使用{},所以需要加上双引号"",因为单引号会将字符串内容转义,所以我们这里使用双引号。.yml配置文件代码:
valuesMap: "{color:'red', language:'Chinese'}"
代码中获取:
@Value("#{${valuesMap}}")
private Map<String,String> otherProperties;
-
- 注入其它bean属性
otherBean是一个Bean对象,name是它的一个属性,可以通过@Value(“#{otherBean.name}”)将这个bean的属性注入@Value声明的属性里
@Value("#{otherBean.name}")
private String someName;
-
- URL资源
与字面量中的字符串类型变量的注入差不多,支持多种形式,我们只示例字符串的形式:
如:
@Value("http://www.baidu.com")
private Resource address;
-
- 操作系统属性
操作系统的属性是静态全局变量systemEnvironment存入,可通过它获取到操作系统的属性。
@Value("#{systemProperties['os.name']}")
private String name;
-
- 文件资源
与字面量中的字符串类型变量的注入差不多,支持多种形式,我们只示例一种。注意这里我们一定要在文件路径前面加上classpath,并且将路径从文件夹处复制过来的时候,最好更改格式,把里面的“\”和“\”改为“/”。当然你也可以不改,Spring Boot也能够识别:
如:
@Value("classpath:D:/code/application/a.txt")private Resource intro;
开发环境的切换
为何需要学习@Profile注解?
由于我们平时在开发中,通常会出现在开发的时候使用一个开发数据库,测试的时候使用一个测试的数据库,而实际部署的时候需要一个数据库。以前的做法是将这些信息写在一个配置文件中,当我把代码部署到测试的环境中,将配置文件改成测试环境;当测试完成,项目需要部署到现在了,又要将配置信息改成现在的。非常麻烦。
而使用了Profile之后,我们就可以分别定义3个配置文件,一个用于开发、一个用户测试、一个用户生产,其分别对应于3个Profile。当在实际运行的时候,只需给定一个参数来激活对应的Profile即可,那么容器就会只加载激活后的配置文件,这样就可以大大省去我们修改配置信息而带来的烦恼。
@Profile/@ActiveProfile注解
spring3.1开始引入,一般用于多环境配置
@Profile注解用于实现通过修改运行时参数,切换不同的开发环境
@Profile注解可以加在类上,也可以加载注入bean的方法上
@Profile只有一个默认的java.lang.String[]类型的属性value,因此它可以指定一个或多个配置名。
@Profile注解,匹配的名字才会去处理,没有匹配的则会被抛弃。
@Profile标签能够定义不同的运行环境,在测试的时候,可以通过
@ActiveProfile来指定运行环境
如何使用两个注解完成环境的切换
开发环境配置:
@Configuration
@PropertySource("classpath:dev.properties")
@Profile("dev")
public class ApplicationDevConfig
{ @Bean
public MyDataSource myDataSource(Environment environment){return new MyDataSource(environment.getProperty("jdbc.username") ,environment.getProperty("jdbc.password") ,environment.getProperty("jdbc.driverClassName") ,environment.getProperty("jdbc.url"));}
}
测试环境配置:
@Configuration
@PropertySource("classpath:test.properties")
@Profile("test")
public class ApplicationTestConfig
{@Beanpublic MyDataSource myDataSource(Environment environment){return new MyDataSource(environment.getProperty("jdbc.username") ,environment.getProperty("jdbc.password"),environment.getProperty("jdbc.driverClassName"),environment.getProperty("jdbc.url"));}
}
主配置:
@Configuration
@Import({ApplicationDevConfig.class,ApplicationTestConfig.class})
public class ApplicationConfig
{
}
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
@ActiveProfiles("test")
public class JavaConfigTest {@Autowiredprivate MyDataSource myDataSource;@Testpublic void someBeanTest(){ System.out.println(myDataSource.toString());}
}
HelloWorld案例
第一个helloWorld案例:
pom.xml:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.5.RELEASE</version><relativePath/>
</parent><!--整合web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
HelloWordController:
@Controller
@SpringBootApplication
public class HelloWordController {@RequestMapping("/helloboot")@ResponseBodypublic String hello() {System.out.println("hello springBoot");return "hello springBoot";}public static void main(String[] args) {SpringApplication.run(HelloWordController.class,args);}
}
运行原理分析:
1,使用 <parent> 继承spring-boot-starter-parent,引入基本的依赖管理配置;
2,引入spring-boot-starter-web,自动引入了springweb相关的包;
@SpringBootApplication 标签做了哪些事情 ?
@SpringBootApplication由三个主要的标签构成:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan
1)@SpringBootConfiguration:本质就是一个@Configuration,代表这是spring容器的主配置类;
2)@EnableAutoConfiguration:开启自动配置,Springboot使用这个标签自动的把内置的符合条件的@Configuration类加载进入应用;
可以查看spring-boot-autoconfigure包中的META-INF/spring.factories文件中的配置项(原理,由@EnableAutoConfiguration标签引入的AutoConfigurationImportSelector类中,使用Spring的SpringFactoriesLoader类实现加载)
3)@ComponentScan:自动扫描;
总结一句话:
@SpringBootApplication:这个注解告诉springboot自动的去完成相关配置,包括基础类的加载,bean的扫描等等,这个后面详细介绍;简单理解为这个标签为我们的应用配置完成了很多基本功能;
SpringApplication.run 又做了哪些事情?
读取配置对象,配置相关自动配置对象,启动tomcat加载应用
总结一句话:
SpringApplication.run:这个是springboot为我们提供的最大的区别,在于springboot不再是一个web应用,需要我们自己去打包,部署,启动tomcat,springboot默认把tomcat打包到应用中,我们可以以正常的运行jar的方式来运行springboot应用;
springBoot项目独立运行方式:
注意:默认的Maven打包方式是不能正常的打包SpringBoot项目的,需要额外的引入打包插件,才能正常的对SpringBoot项目 打成jar包,以后只要拿到该jar包就能脱离IDE工具独立运行了
-
- 使用插件 springboot:run
添加插件
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
对于eclipse 项目要打包,引入插件之后 直接用 package 命令、
对于idea直接点击打包插件即可
-
- 打包独立运行
执行java -jar xxx.jar 运行(在字节码编译目录中会有打包好的 jar)
-
- 使用main方法启动
方式一:直接调用run方法
SpringApplication.run(StartModeController.class,args);
方式二:可以通过创建对象的方式来运行SpringApplication
SpringApplication application = new SpringApplication(StartModeController.class); application.run(args);
方式三:通过builder完成:
SpringApplication application = new SpringApplicationBuilder(StartModeController.class).build();application.run(args);
Springboot的优缺点:
创建独立的Spring应用程序
嵌入的Tomcat,无需部署WAR文件
简化Maven配置
自动配置Spring
提供生产就绪型功能,如日志,健康检查和外部配置
XML没有要求配置
非常容易和第三方框架集成起来;
缺点:
1,版本更新较快,可能出现较大变化;
2,因为约定大于配置,所以经常会出现一些很难解决的问题;
Springboot基本使用
应用构建
使用官网进行构建springboot项目
构建项目的地址:http://start.spring.io/
使用开发工具构建springboot项目
新建一个项目 ,选则 spring Initializr 选项。
填写相关的信息。选则相关的jar依赖。
热部署
直接添加
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional>
</dependency>
即可
可以在application.properties文件中设置一些属性
#默认排除的资源 spring.devtools.restart.exclude=static/**,templates/**,public/** #增加额外的排除资源
spring.devtools.restart.additional-exclude=public/** #处理默认配置排除之外的 spring.devtools.restart.enabled=false #禁用自动重启
热部署的原理
SpringBoot重启是restart重启,通过监控classpath的变化,如果classpath中的文件发生变化,即出发重启。springboot通过两个classpath来完成reload,一个basic classloader中加载不变的类,一个restart classloader中加载classpath中的类,重启的时候,restart classloader中的类丢弃并重新加载,所以
设置自动编译:如果您觉得 SpringBoot的热部署不怎么好用,那你也可以去掉热部署的依赖,使用自动编译:
1,开启自动编译 :setting -> Build... -> compiler -> Build project automatically
2,ctrl + alt + shift +/ -> registry -> compiler.automake.allow.when.app.running
设置banner
1,可以直接在classpath下添加一个banner.txt文件即可;
2,介绍springboot的配置文件。springboot默认在classpath中通过application.properties文件来进行配置;比如:
spring.main.banner-mode=off
就可以关闭banner输出
SpringApplication的参数
可以通过注入一个ApplicationArguments对象来完成参数的封装;
@Autowired
private ApplicationArguments args;@RequestMapping("/args")public String args() {return args.getNonOptionArgs().toString();
}
Springboot开发WEB应用
集成日志框架
为什么要用日志?
1,比起System.out.println,日志框架可以把日志的输出和代码分离;
2,日志框架可以方便的定义日志的输出环境,控制台,文件,数据库;
3,日志框架可以方便的定义日志的输出格式和输出级别;
java常用日志框架类别介绍
-
- Log4j
Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。
-
- Log4j 2
Apache Log4j 2是apache开发的一款Log4j的升级产品。
-
- Commons Logging
Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging。
-
- Slf4j
类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)。
-
- Logback
一套日志组件的实现(slf4j阵营)。
Java常用日志框架历史
1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j。后来Log4j成为Apache基金会项目中的一员。
期间Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议sun引入Log4j到java的标准库中,但Sun拒绝了。
2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,log4j就已经成为一项成熟的技术,使得log4j在选择上占据了一定的优势。
接着,Apache推出了Jakarta Commons Logging,JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是log4j,也可以是Java Util Logging。
后来(2006年),Ceki Gülcü不适应Apache的工作方式,离开了Apache。然后先后创建了slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。
Apache眼看有被Logback反超的势头,于2012-07重写了log4j 1.x,成立了新的项目Log4j 2。Log4j 2具有logback的所有特性。Log4j2与Log4j1发生了很大的变化,log4j2不兼容log4j1。
Springboot的默认日志使用
1,Springboot默认已经开启日志;默认的日志格式为:时间 日志级别 PID 线程名称 日志类 日志说明
2,Springboot的日志区别系统日志和应用日志;
3,Springboot推荐使用Logback作为日志框架
Logback使用方法(推荐使用logback自己的配置文件)
1,springboot默认支持logback.xml或者logback-spring.xml,推荐使用logback-spring.xml,springboot会增加额外功能;
2,可以通过logging.config=classpath:mylogback.xml指定自己的logback配置文件(不推荐);
3,一个典型的logback配置文件:
Logback使用介绍:
使用日志框架的步骤:
a. 在resources文件夹下面创建一个xml文件,文件的名称使用 logback-spring.xml。
b. 在logback-spring.xml文件中编写日志文件的内容:
<?xml version="1.0" encoding="utf-8" ?>
<configuration><!--日志的输出方式: 输出到控制台--><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern></encoder></appender><!--配置日志的类型以及输出日志的级别: 使用系统的日志, 日志级别为info--><root level="info"><!--必须要和appender中的name属性的值保持一致--><appender-ref ref="STDOUT"/></root>
</configuration>
c.启动项目即可。
参考日志格式:
%d{yyyy-MM-dd-HH:mm:ss} %level [%thread]-%class:%line >> %msg %n
格式中的标识符组成:
%logger{n}: 输出Logger对象类名,n代表长度
%class{n}: 输出所在类名,
%d{pattern}或者date{pattern}: 输出日志日期,格式同java %L/line: 日志所在行号
%m/msg: 日志内容
%method: 所在方法名称
%p/level: 日志级别
%thread: 所在线程名称
关于logback-spring.xml配置文件的详细解析:
1,configuration:Logback配置根元素
属性包括:
a,scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。b,scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。c,debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
子元素:
<contextName>:上下文名字;
<property>:定义属性,可以使用${}在配置文件中使用;
2,appender:在logback中是用于具体记录日志的组件,可以用来配置日志记录方式,日志记录格式等;
属性包括:
name:appender的名字,用于下面在配置日志的时候指定;
class:使用到的appender类;
常见的appender:
1,ch.qos.logback.core.ConsoleAppender:输出到控制台;
<!--输出到控制台-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--日志格式化--><encoder><pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern></encoder>
</appender>
2,ch.qos.logback.core.FileAppender:输出到文件;
file:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
append:文件结尾,如果是 false,清空现存文件,默认是true。
encoder:对日志进行格式化 <!--输出到文件中-->
<appender name="FILE" class="ch.qos.logback.core.FileAppender"><encoder><pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern></encoder><append>false</append><file>mylog.log</file>
</appender>
3,ch.qos.logback.core.rolling.RollingFileAppender:输出到文件,可以配置滚动策略,当日志达到某个条件之后分文件记录;
append:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
rollingPolicy:滚动策略,涉及文件移动和重命名。
常用滚动策略:
ch.qos.logback.core.rolling.TimeBasedRollingPolicy:按照时间控制来控制记录文件;
fileNamePattern:文件名称格式,以%d{pattern};
maxHistory: 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。(以文件最小时间为准)<!--输出到文件,可以设置文件滚动(分割)条件按照时间分割-->
<appender name="RollingTimeFile" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder><pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern></encoder><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>mylog.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>30</maxHistory></rollingPolicy>
</appender>
ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy:按照时间和大小控制记录文件;
fileNamePattern:文件名称格式,可以使用%i来控制索引编号;
maxFileSize:这是活动文件的大小,默认值是10MB
maxHistory:可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。(以文件最小时间为准)<!--输出到文件,可以设置文件滚动(分割)条件按照文件大小分割-->
<appender name="RollingSizeFile" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder><pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern></encoder><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>mylog.%d{yyyy-MM-dd}.%i.log</fileNamePattern><maxFileSize>1kb</maxFileSize><maxHistory>30</maxHistory></rollingPolicy>
</appender>
<logger>元素:用来设置某一个包或具体的某一个类的日志打印级别及对应的appender;
属性:
name: 用来指定受此loger约束的某一个包或者具体的某一个类;
子节点:
appender-ref:可以配置多个,标识这个appender将会添加到这个logger
如:
<!--使用自己的日志-->
<logger level="trace" name="cn.wolfcode.springboot"><appender-ref ref="STDOUT"/>
</logger>
<root>元素:特殊的logger,代表根配置,如果没有单独指定日志包层级,都默认使用root定义的日志输出级别;
属性:
level:指定日志级别;
如:
<!--使用系统的日志-->
<root level="info"><appender-ref ref="STDOUT"/>
</root>
在代码中可以使用自定义的Logger对象,输出日志信息。
实现的方式一:通过LoggerFactory工厂对象创建Logger对象
// 方式一:自己定义一个Logger对象private static final Logger LOGGER = LoggerFactory.getLogger(LogController.class);@RequestMapping("/log")@ResponseBodypublic String log() {// 方式一的出生日志的方式LOGGER.info("方式一:我是info");LOGGER.debug("方式一:我是debug");LOGGER.error("方式一:我是error");return "log";}
实现的方式二:使用注解的方式
@Slf4j // 方式二:使用注解来输出日志,前提是需要依赖lombok包
public class LogController {@RequestMapping("/log")@ResponseBodypublic String log() {// 方式二的输出方式log.trace("方式二: trace信息");log.debug("方式二: debug信息");log.info("方式二: info{}信息", 33333);log.error("方式二: error信息");return "log";}
SpringBoot项目的目录结构
我们通过idea创建出来的SpringBoot项目,会生成一个标准的项目的目录结构。
application.properties优先级
一个项目中可以有多个application.properties文件存放在不同目录中,此时他们会遵循固定的优先级来处理有冲突的属性配置
项目/config/application.properties
项目/application.properties
classpath:config/application.properties
classpath:application.properties
一般都在classpath:application.properties做配置,其他方式不使用
静态资源
默认情况下,Springboot会从classpath下的 /static , /public , /resources , /META-INF/resources下加载静态资源
可以在application.properties中配置spring.resources.staticLocations属性来修改静态资源加载地址
spring.resources.static-locations=classpath:/hello
注意设置完以后,会覆盖之前的设置。
- 因为应用是打成jar包,所以之前的src/main/webapp就作废了,如果有文件上传,那么就的必须去配置图片所在的路径
spring.resources.static-locations=classpath:/static,file:///Users/tony/Desktop/image/
集成Freemarker
为何要集成Freemarker
1.性能。velocity应该是最好的,其次是jsp,普通的页面freemarker性能最差(虽然只是几毫秒到十几毫秒的差距)。但是在复杂页面上(包含大量判断、日期金额格式化)的页面上,freemarker的性能比使用tag和el的jsp好。
2、宏定义比jsp tag方便
3、内置大量常用功能。比如html过滤,日期金额格式化等等,使用非常方便
4、支持jsp标签
5、可以实现严格的mvc分离
6、易学易用
我是看了一天文档就用得挺熟练了,freemarker文档写得太好了,例子丰富,照做一遍全都会了。
7、功能强大
比Velocity强大多了,还支持JSP Tag。不过最有意义的是macro功能,可以自定义常用的macro,实现页面常规操作的可复用性。
8、报错信息友好
很多应用服务器的JSP报错信息是无法定位到源代码行的。不过freemarker报错定位很准确,丝毫不差,而且信息丰富,一看就知道怎么回事(虽然那个黄黄的页面看起来让人难受)
与JSP相比,FreeMarker的一个优点在于不能轻易突破模板语言开始编写Java代码,因此降低了领域逻辑漏进视图层的危险几率。但缺点是需要一点附加配置来将其平稳地集成到应用程序中,一些IDE(集成开发环境)可能并不完全支持它,当然还有开发者或设计者也许需要学习一门陌生的模板语言。相关的JAR文件将要添加到WEB-INF/lib(在需要的时候,它们包含在Spring中) 。
Freemarker的一些常见语法回顾
获取当前日期,必须要格式化显示
<input value="${.now?string('yyyy-MM-dd')}"/>
获取Controller控制器中共享给页面的对象中的普通属性
<input id="${user.name}" name="${user.name}" value="${user.name}"/>
获取Controller控制器中共享给页面的对象中的日期类型属性,必须要格式化显示
<input value="${(user.birthday?string('yyyy-MM-dd'))!}"/>
获取Controller控制器中共享给页面的对象中的boolean类型属性,必须要处理显示
<input value="${user.active?string("是","否")}">
对null 或者不存在的对象进行取值,可以设置默认值
例:${var!'我是默认值'}
即,有值时显示正常值,无值时显示默认值
如果需要判断,使用if标签判断
<#--判断是否小于25-->
<#if user.age < 25 >young
<#else>old
</#if>
<br/>
<#--判断是否大于25-->
<#if user.age > 25 >old
<#else>young
</#if>
如果需要判断,可以使用switch标签判断
<#switch user.age><#case 30>very old<#break ><#case 25>old<#break ><#default >young<#break ></#switch>
获取Controller控制器中共享给页面的list集合,必须要遍历进行显示
<#list userList as person><tr><td>${person.name}</td><td>${(person.age>25) ?string("old","young")}</td><td>${(person.birthday?string('yyyy-MM-dd hh:mm:ss'))!}</td><td>${person.active?string("是","否")}</td></tr>
</#list>
userList 这个名字必须和controller控制器中的共享的key保持一致。
获取Controller控制器中共享给页面的map集合,必须要遍历进行显示
<#list map?keys as key>${key}:${map[key]}<br/>
</#list>
map 这个名字必须和controller控制器中的共享的key保持一致。
自定义变量
<#assign num = 100 />
自定义的变量参与计算
<font color="red"> ${num * 10} </font><br>
处理list集合
first: 取List值第一个值<br/>
<span>${userList?first}</span>last: 取List值最后一个值<br/>
<span>${userList?last}</span>size: 集合大小<br/>
<span>${userList?size}</span>sort: 对集合进行排序<br/>
<#list userList?sort as item>
<span>${item.name}</span>
</#list>
<br/>
如何集成Freemarker
-
- 导入相关的依赖:
<!--整合freemarker--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency>
-
- 在resources/templates目录下面创建对应的freemarker模板。
freemarker.ftl:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title>
</head>
<body>
<table><tr><th>姓名</th><th>年龄</th><th>备注</th><th>生日</th><th>是否激活</th></tr><#list userList as person><tr><td>${person.name}</td><td>${person.age}</td><td>${(person.age>25) ?string("old","young")}</td><td>${(person.birthday?string('yyyy-MM-dd hh:mm:ss'))!} </td><td>${person.active?string("是","否")}</td></tr></#list></body>
</table>
-
- 编写相应的Controller
FreemarkerController:
@Controller
@RequestMapping("/freemarker")
public class FreemarkerController {@RequestMapping("/hello")public String hello(ModelMap map) {User u = new User();u.setName("haozz");u.setAge(24);u.setPassword("qwerty");u.setBirthday(new Date());u.setBirthday(null);u.setActive(false);User u1 = new User();u1.setName("nico robin");u1.setAge(35);u1.setPassword("qwerty");u1.setBirthday(new Date());u1.setActive(true);List<User> userList = new ArrayList<>();userList.add(u);userList.add(u1);map.addAttribute("userList",userList);return "freemarker"; }
集成原理
SpringBoot的自动配置中含有FreeMarkerAutoConfiguration配置对象,该配置对象又导入了 FreeMarkerReactiveWebConfiguration配置对象,在里面创建了FreeMarkerConfigurer和FreeMarkerViewResolve 两个对象交给Spring管理,并且设置了默认的属性值,这些属性值来源于FreeMarkerProperties对象
常见的属性配置
spring.freemarker.enabled=true: 是否开启freemarker支持spring.freemarker.allow-request-override: 是否允许request中的属性覆盖model中同名属性,默认false spring.freemarker.allow-session-override: 是否允许session中的属性覆盖model中同名属性,默认false spring.freemarker.cache: 是否支持模板缓存,默认falsespring.freemarker.charset=UTF-8: 模板编码spring.freemarker.content-type=text/html: 模板contenttype spring.freemarker.expose-request-attributes: 是否开启request属性暴露,默认falsespring.freemarker.expose-session-attributes: 是否开启session属性暴露,默认false spring.freemarker.expose-spring-macro-helpers: 是否开启spring的freemarker宏支持,默认为false spring.freemarker.prefer-file-system-access: 默认为true,支持实时检查模板修改 spring.freemarker.prefix: 加载模板时候的前缀spring.freemarker.settings.*: 直接配置freemarker参数spring.freemarker.suffix: 模板文件后缀 spring.freemarker.template-loader-path=classpath:/templates/: 模板加载地址
集成Thymeleaf
为何要集成Thymeleaf
Thymeleaf是个XML/XHTML/HTML5模板引擎,可以用于Web与非Web应用。
Thymeleaf的主要目标在于提供一种可被浏览器正确显示的、格式良好的模板创建方式,因此也可以用作静态建模。你可以使用它创建经过验证的XML与HTML模板。相对于编写逻辑或代码,开发者只需将标签属性添加到模板中即可。接下来,这些标签属性就会在DOM(文档对象模型)上执行预先制定好的逻辑。Thymeleaf的可扩展性也非常棒。你可以使用它定义自己的模板属性集合,这样就可以计算自定义表达式并使用自定义逻辑。这意味着Thymeleaf还可以作为模板引擎框架。
thymeleaf优点:静态html嵌入标签属性,浏览器可以直接打开模板文件,便于前后端联调。
Thymeleaf模板引擎是springboot中默认配置,与freemarker相似,可以完全取代jsp,在springboot中,它的默认路径是src/main/resources/templates 静态文件css, js 等文件默认路径是src/main/resources/static,所有项目中如果没有这个目录需要手动加上了
Thymeleaf的一些常见语法回顾
获取Controller控制器中共享给页面的对象中的普通属性
<input th:value="${user.age}"/>
获取Controller控制器中共享给页面的对象中的日期类型属性
<input th:value="${#dates.format(user.birthday,'yyyy-MM-dd')}"/>
获取Controller控制器中共享给页面的对象中的boolean类型属性
<td th:text="${person.flag}"></td>
获取Controller控制器中共享给页面的list集合,必须要遍历进行显示
<tr th:each="person:${userList}"><td th:text="${person.name}"></td><td th:text="${person.age ge 25} ? old : young"></td><td th:text="${#dates.format(person.birthday,'yyyy-MM-dd hh:mm:ss')}"></td><td th:text="${person.flag}"></td>
</tr>
如果需要判断,使用if标签判断
<div th:if="${user.age lt 25}">young</div>
如果需要判断,可以使用switch标签判断
<div th:switch="${user.name}"><p th:case="'haozz'">最帅的</p><p th:case="'nico robin'">妮可罗宾</p><p th:case="'nami'">娜美</p>
</div>
处理表单(action跳转地址,method设置请求方式,object抽取相同的部分)
<form th:action="@{/th/postform}" th:object="${user}" th:method="post">
<!--th:field="*{name}"相当于id="name" name="name" value="具体的name值"-->
<input type="text" th:field="*{name}"/>
<input type="submit"/>
</form>
处理html内容被解析,转译
<span th:utext="${user.desc}"></span>
th:utext 会进行转译<br/>
th:text 不会进行转译<br/>
常见的th标签汇总
如何集成Thymeleaf
-
- 导入相关的依赖。
<!--整合thymeleaf-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
-
- 在resources/templates目录下面创建对应的thymeleaf模板。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:method="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<table><tr><th>姓名</th><th>年龄</th><th>备注</th><th>生日</th><th>婚否</th></tr><tr th:each="person:${userList}"><td th:text="${person.name}"></td><td th:text="${person.age}"></td><td th:text="${person.age ge 25} ? old : young"></td><td th:text="${#dates.format(person.birthday,'yyyy-MM-dd hh:mm:ss')}"></td><td th:text="${person.active}"></td></tr>
</table>
</body>
</html>
-
- 编写相应的Controller
@Controller
@RequestMapping("/freemarker")
public class FreemarkerController {@RequestMapping("/hello")public String hello(ModelMap map) {User u = new User();u.setName("haozz");u.setAge(24);u.setPassword("qwerty");u.setBirthday(new Date());u.setBirthday(null);u.setActive(false);User u1 = new User();u1.setName("nico robin");u1.setAge(35);u1.setPassword("qwerty");u1.setBirthday(new Date());u1.setActive(true);List<User> userList = new ArrayList<>();userList.add(u);userList.add(u1);map.addAttribute("userList",userList);return "freemarker"; }
集成原理
SpringBoot的自动配置中含有ThymeleafAutoConfiguration配置对象,该配置对象的里面创建了视图解析器ThymeleafViewResolver和模板引擎 SpringTemplateEngine 和模板解析器SpringResourceTemplateResolver 三个对象交给Spring管理,并且设置了默认的属性值,这些属性值来源于ThymeleafProperties对象
常见属性设置
spring.thymeleaf.prefix=classpath:/templates/ 设置thymeleaf路径默认为src/main/resources/templates
spring.thymeleaf.suffix=.html 设置thymeleaf模板后缀
spring.thymeleaf.content-type=text/html
spring.thymeleaf.cache=false 是否开启缓存默认为true
spring.thymeleaf.mode=LEGACYHTML5 设置thymeleaf严格校验
spring.thymeleaf.encoding=UTF-8 设置编码
了解@ConfigurtionProperties注解的用法:
属性名匹配规则
@ConfigurationProperties的属性名匹配规则(Relaxed binding):Spring Boot可以对下面四种类型的命名进行自动匹配,也就是说配置文件和类文件中的名称不需要完全相同,使用下面的任意两种,系统就会将二者匹配上
标准方式:变量之间通过下一个单词的首字母大写的方式隔开,
eg:student.isFemale
使用“-”进行单词之间的连接:
eg:student.is-female
使用“_”进行单词之间的连接:
eg:student.is_female
全部大写,使用“_”连接:通常对系统属性变量推荐这种写法。
eg:STUDENT_IS_FEMALE
属性ignoreInvalidFields
标记当有非法字段绑定到这个对象时可以被忽略。"非法"指根据使用的binder非法,通常这意味着字段类型错误(或者无法强制转为正确的类型).默认false。这意味着不能忽略字段非法,所以只能报错
属性ignoreUnknownFields
标记当有未知字段绑定到这个对象时可以被忽略。未知字段可能是属性中的一个符号错误。默认true。
属性prefix/value
要绑定到这个对象的有效的属性的名字前缀。value 和 prefix 是同义词
案例如下:
@ConfigurationProperties(prefix = "spring.datasource")
@Setter@Getter@ToString
@Repository
public class MyDataSource {private String username;private String url;private String password;private String driverClassName;
}application.properties:spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql:///crm
spring.datasource.username=root
spring.datasource.password=root123
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource@Controller
@SpringBootApplication
public class DataSourcesController {@Autowiredprivate MyDataSource myDataSource;@RequestMapping("/source")@ResponseBodypublic String hello() {return myDataSource.toString();}public static void main(String[] args) {SpringApplication.run(App.class,args);}
}
集成Druid连接池
为何要集成Druid
1、性能方面 hikariCP>druid>tomcat-jdbc>dbcp>c3p0 。hikariCP的高性能得益于最大限度的避免锁竞争。
2、druid功能最为全面,sql拦截等功能,统计数据较为全面,具有良好的扩展性。
3、综合性能,扩展性等方面,可考虑使用druid或者hikariCP连接池,比较方便对jdbc接口进行监控跟踪等。
4、可开启prepareStatement缓存,对性能会有大概20%的提升。
psCache是connection私有的,所以不存在线程竞争的问题,开启pscache不会存在竞争的性能损耗。
psCache的key为prepare执行的sql和catalog等,value对应的为prepareStatement对象。开启缓存主要是减少了解析sql的开销。
5、3p0历史悠久,代码及其复杂,不利于维护。并且存在deadlock的潜在风险。
6、Druid可以打印SQL,慢查询方面的日志
回顾Druid连接池在SSM框架中的用法
在pom.xml文件中导入依赖:
<!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version><scope>runtime</scope></dependency><!-- druid连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.26</version></dependency><!--spring jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency>
spring的主配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!--组件扫描器--><context:component-scan base-package="cn.wolfcode.crm"/><!--自动DI解析器--><context:annotation-config/><!--加载数据库的配置信息--><context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/><!-- 连接池对象 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"init-method="init" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="username" value="${jdbc.username}"/><property name="url" value="${jdbc.url}"/><property name="password" value="${jdbc.password}"/></bean>
</beans>
如何集成Druid
方式一
pom.xml:
<!--整合DrudiDataSource--><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency><!--jdbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>
application.properties:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql:///crm
spring.datasource.username=root
spring.datasource.password=root123
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
方式二
pom.xml:
<!--整合DrudiDataSource--><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency><!--jdbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>
application.properties:
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql:///crm
spring.datasource.druid.username=root
spring.datasource.druid.password=root123
测试案例:
@RestController
public class DataSourceController {@Autowiredprivate DataSource dataSource;@RequestMapping("/dataSource")public String showData() throws SQLException {return dataSource.getConnection().toString();}
}
集成原理
SpringBoot的自动配置中含有DataSourceAutoConfiguration配置对象,该配置对象含有个内部类,该内部类也是配置 类,当容器中没有连接池对象时,就会Generic方式来创建连接池对象交给Spring管理,用到是属性值来源于 DataSourceProperties对象
集成Junit框架
为何要集成Junit
我们在开发的过程中,肯定需要不断的对我们自己写的代码进行测试。所以离不开Junit单元测试。
- 导入依赖:
<!--junit-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency>
- 准备配置类
public class SomBean {public SomBean() {System.out.println("构造器");}
}
@Configuration
public class JunitConfig {@Beanpublic SomBean somBean(){return new SomBean();}
}
- 编写测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JunitConfig.class)
public class App
{@Autowiredprivate SomBean somBean;@Testpublic void test(){System.out.println("somBean = " + somBean);}}
集成MyBatis框架
为何要集成MyBatis
1、简单易学
mybatis本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
2、灵活
mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
3、解除sql与程序代码的耦合
通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
4、提供映射标签,支持对象与数据库的orm字段关系映射
5、提供对象关系映射标签,支持对象关系组建维护
6、提供xml标签,支持编写动态sql(主要优势之一)。
回顾MyBatis在之前SSM框架中集成的方式
pom.xml:
<!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><!-- mybatis-spring --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.0</version></dependency>
applicationContext.xml:
<!-- 配置SessionFactory --><bean id="sessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 1:连接池 --><property name="dataSource" ref="dataSource"/><!-- 2:读取MyBatis总配置文件 --><property name="configLocation" value="classpath:mybatis.xml"/><!-- 3:配置别名扫描 --><property name="typeAliasesPackage" value="cn.wolfcode.crm.domain"/><!-- 4:加载mapper文件 --><property name="mapperLocations" value="classpath:cn/wolfcode/crm/mapper/*Mapper.xml"/><!--集成pagehelper--><property name="plugins"><array><bean class="com.github.pagehelper.PageInterceptor"><!-- 这里的几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置 --><property name="properties"><value>helperDialect=mysqlreasonable=truepageSizeZero=true</value></property></bean></array></property></bean><!--Mapper接口代理扫描器--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="cn.wolfcode.crm.mapper"/></bean>
mybatisCfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><settings><!--配置允许懒加载--><setting name="lazyLoadingEnabled" value="true"/><!--取消关联查询积极性--><setting name="aggressiveLazyLoading" value="false"/><!--哪些方法触发关系查询--><setting name="lazyLoadTriggerMethods" value="clone"/></settings>
</configuration>
如何集成MyBatis
pom.xml:
<!--整合mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.0</version></dependency>
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><settings><!--配置允许懒加载--><setting name="lazyLoadingEnabled" value="true"/><!--取消关联查询积极性--><setting name="aggressiveLazyLoading" value="false"/><!--哪些方法触发关系查询--><setting name="lazyLoadTriggerMethods" value="clone"/></settings>
</configuration>
application.properties:
#mybatis
#给包起别名,因为使用MBG生成的mapper,
#sql里面默认是使用的类的全限定名,因此我们可以不配别名,都使用全名
#mybatis.type-aliases-package=cn.wolfcode.springboot.integrase._5_mybatis.domain
#加载mybatis的主配置文件
mybatis.config-location=classpath:mybatis-config.xml我们也可以去掉MyBatis的主配置文件:把懒加载的配置配置到SpringBoot的配置文件中:如:mybatis.configuration.lazy-load-trigger-methods=clone
mybatis.configuration.aggressive-lazy-loading=false
mybatis.configuration.lazy-loading-enabled=true
domain:
@Setter
@Getter
@ToString
public class Department {private Long id;private String name;private String sn;}
mapper:
public interface DepartmentMapper {List<Department> selectAll();}
mapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.wolfcode.springboot._06_mybatis.mapper.DepartmentMapper"><select id="selectAll"resultType="cn.wolfcode.springboot._06_mybatis.domain.Department">select id,name,sn from department</select>
</mapper>
主配置类:
注意:通过@MapperScan扫描器来扫描mapper的接口
@SpringBootApplication
@MapperScan("cn.wolfcode.springboot._06_mybatis.mapper")
public class MyBatisConfig {}
App测试类:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyBatisConfig.class)
public class App
{@Autowiredprivate DepartmentMapper departmentMapper;@Testpublic void test(){List<Department> list = departmentMapper.selectAll();list.forEach(System.out::println);}
}
常见属性
#懒加载
mybatis.configuration.lazy-loading-enabled=true mybatis.configuration.lazy-load-trigger-methods=clone mybatis.mapper-locations=classpath:cn/wolfcode/xxx/mapper/*Mapper.xml mybatis.type-aliases-package=cn.wolfcode.xxx.domain #连接池对象不用配置,会自动注入
集成PageHelper
回顾PageHelper在之前SSM框架中集成的方式
pom.xml:
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.6</version></dependency>
配置文件中配置pageHelper
方式一:分页插件配置在mybatis的主配置文件中
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><settings><!--配置允许懒加载--><setting name="lazyLoadingEnabled" value="true"/><!--取消关联查询积极性--><setting name="aggressiveLazyLoading" value="false"/><!--哪些方法触发关系查询--><setting name="lazyLoadTriggerMethods" value="clone"/></settings><!--配置在Spring中--><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><property name="reasonable" value="true"/><property name="helperDialect" value="mysql"/><property name="pageSizeZero" value="true"/></plugin></plugins></configuration>
方式二:分页插件配置在spring的配置文件中
<!-- 配置SessionFactory --><bean id="sessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 1:连接池 --><property name="dataSource" ref="dataSource"/><!-- 2:读取MyBatis总配置文件 --><property name="configLocation" value="classpath:mybatis.xml"/><!-- 3:配置别名扫描 --><property name="typeAliasesPackage" value="cn.wolfcode.crm.domain"/><!-- 4:加载mapper文件 --><property name="mapperLocations" value="classpath:cn/wolfcode/crm/mapper/*Mapper.xml"/><!--集成pagehelper--><property name="plugins"><array><bean class="com.github.pagehelper.PageInterceptor"><!-- 这里的几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置 --><property name="properties"><value>helperDialect=mysqlreasonable=truepageSizeZero=true</value></property></bean></array></property></bean>
如何集成PageHelper
pom.xml:
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.2.10</version>
</dependency>
application.properties:
#pageHelper
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.page-size-zero=true
集成事务管理
回顾事务管理在之前SSM框架中的使用
方式一:在spring的xml配置文件中
<!-- 配置事务 --><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="get*" read-only="true"/><tx:method name="list*" read-only="true"/><tx:method name="query*" read-only="true"/><tx:method name="*" propagation="REQUIRED"/></tx:attributes></tx:advice><aop:config><aop:pointcut expression="execution(* cn.wolfcode.crm.service.*Service.*(..))" id="txPoint"/><aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/></aop:config>
方式二:使用注解的方式
<!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 启用事务注解 --><tx:annotation-driven transaction-manager="transactionManager"/>
Spring中注解的方式@Transactional标注事务方法。为了将方法定义为支持事务处理,可以在方法上添加@Transactional注解。根据Spring AOP基于代理机制,只能标注公有方法。如果在类上标注@Transactional注解,那么这个类中所有公有方法都会被定义为支持事务。
代码如下:
//添加事务注解//1.使用 propagation 指定事务的传播行为, 即当前的事务方法被另外一个事务方法调用时//如何使用事务, 默认取值为 REQUIRED, 即使用调用方法的事务//REQUIRES_NEW: 事务自己的事务, 调用的事务方法的事务被挂起. //2.使用 isolation 指定事务的隔离级别, 最常用的取值为 READ_COMMITTED//3.默认情况下 Spring 的声明式事务对所有的运行时异常进行回滚. 也可以通过对应的//属性进行设置. 通常情况下去默认值即可. //4.使用 readOnly 指定事务是否为只读. 表示这个事务只读取数据但不更新数据, //这样可以帮助数据库引擎优化事务. 若真的事一个只读取数据库值的方法, 应设置 readOnly=true//5.使用 timeout 指定强制回滚之前事务可以占用的时间.@Transactional(propagation=Propagation.REQUIRES_NEW,isolation=Isolation.READ_COMMITTED,noRollbackFor={UserAccountException.class},rollbackFor = IOException.class,readOnly=false,timeout=3)@Overridepublic void purchase(String username, String isbn) {}
注意有一种情况事务会失效:
@Transactional@Overridepublic void purchase(String username, String isbn) {this.update(username, isbn);}@Transactionalpublic void update(String username, String isbn) {// TO DO}
失效的原因是:
因为spring事务是基于aop的代理机制,当方法中调用this本身的方法时候即使在this的方法标明事务注解,但是事务注解会失效。
解决办法:
在配置中添加如下内容
<!--开启aspectj代理,并暴露aop代理到ThreadLocal-->
<aop:aspectj-autoproxy expose-proxy="true"/>
将上述调用的地方改成如下:
@Transactional
@Override
public void purchase(String username, String isbn) {((BookShopServiceImpl)AopContext.currentProxy()).update(username, isbn);
}
如何集成事务管理
方式一: 使用注解的方式
在Service的实现类上面添加@Transactional注解即可。
如果是使用的springboot的较低版本,需要在配置类上面使用@EnableTransactionManagement开启注解,可以理解为相当于
<tx:annotation-driven transaction-manager="transactionManager"/>
方式二:使用xml文件的方式
- 提供一个配置事务的xml文件。
<!-- 3:配置事务管理 --><!-- 3w: what where when --><!-- 3.1:what 做什么增强 --><bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 3.2:where: 在哪个包哪个类哪个方法下做增强 --><aop:config> <aop:pointcut expression="execution( * cn.wolfcode.crm.service.*Service.*(..))" id="pc"/><aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/></aop:config><!-- 3.3:when :在什么时候做增强 --><tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="get*" read-only="true"/><tx:method name="list*" read-only="true"/><tx:method name="select*" read-only="true"/><tx:method name="query*" read-only="true"/><tx:method name="check*" read-only="true"/><tx:method name="*" propagation="REQUIRED"/></tx:attributes></tx:advice>
2.在主配置文件中通过@ImportResources
@ImportResource("classpath:tx.xml")
集成FastJSON
为何要集成FastJSON
fastjson可以只依赖于jdk环境,其他的条件可以不用依赖
fastjson可以进行序列化和反序列换(所谓的序列化就是将对象转换成对应的json字符串,反序列化就是将json字符串进行转换成对应的对象)
fastjson进行json转换的的速度远远大于jackjson
回顾FastJSON在之前SSM框架中的使用
pom.xml:
<!--fastJson解析json --><dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version>
</dependency>
mvc.xml
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true"><!-- 配置Fastjson支持 --><bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json</value><value>application/xml;charset=UTF-8</value> </list></property><property name="features"><list><!--配置返回json字符串是返回null值 --><value>WriteMapNullValue</value><value>QuoteFieldNames</value><!-- 配置日期格式化 --><value>WriteDateUseDateFormat</value></list></property></bean></mvc:message-converters>
</mvc:annotation-driven>
@jsonFiled(format="yyyy-MM-dd HH:mm:ss")
private Date creadate;
如何集成FastJSON
pom.xml:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version>
</dependency>
方式一:
在一个配置类中定义一个bean
@Bean
public HttpMessageConverters fastjsonHttpMessageConverters(){
//定义一个convert转换消息的对象
FastJsonHttpMessageConverter converter=new FastJsonHttpMessageConverter();//添加fastjson的配置信息,比如是否要格式化返回的json信息
FastJsonConfig fastJsonConfig=new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
//解决fastjson 中文乱码
List<MediaType> fastMediaTypes = new ArrayList<MediaType>();fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);//将配置信息添加到convert中
converter.setFastJsonConfig(fastJsonConfig);
//将编码配置加入convert中
converter.setSupportedMediaTypes(fastMediaTypes);
HttpMessageConverter<?> httpMessageConverter=converter;
return new HttpMessageConverters(converter);
}
方式二:
让配置类实现 接口 WebMvcConfigurer ,然后覆盖一个方法configureMessageConverters 如:
@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {// 1、需要先定义一个 convert 转换消息的对象;FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();//2、添加fastJson 的配置信息,比如:是否要格式化返回的json数据;FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);//3、在convert中添加配置信息.fastConverter.setFastJsonConfig(fastJsonConfig);//4、将convert添加到converters当中.converters.add(fastConverter);}
注解:
// 输出到页面,格式化日期格式
@JSONField(format = "yyyy-MM-dd")
// serialize:是否需要序列化属性.如果设置成false,页面上就不会出现
@JSONField(serialize = false)
集成Jackson
SPringBoot已经集成了Jackson,所以我们不需要导入依赖。可直接使用。
private Long id;private String name;// 输出日期到表单,进行格式化 。注意:必须要带上时区,不然时间会减少一天@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")// 接收表单传来到日期,进行格式化。@DateTimeFormat(pattern ="yyyy-MM-dd")private Date hiredate;@JsonIgnore // 忽略该属性在浏览器中进行显示数据private String password;
集成SpringData JPA
JPA是什么
SpringData:其实SpringData就是Spring提供了一个操作数据的框架。而SpringData JPA只是SpringData框架下的一个基于JPA标准操作数据的模块。
SpringData JPA:基于JPA的标准数据进行操作。简化操作持久层的代码。只需要编写接口就可以。
如何集成JPA
- 导入依赖
<!--jpa--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
- application.properties文件中添加配置
#jpa
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
- 实体类
@Entity
@Table(name="role")
public class Role {@Id //主键id@GeneratedValue(strategy = GenerationType.IDENTITY)//主键生成策略@Column(name = "id")//数据库字段名private Long id;@Column(name = "name")private String name;@Column(name = "sn")private String sn;@Overridepublic String toString() {return "Role{" +"id=" + id +", name='" + name + '\'' +", sn='" + sn + '\'' +'}';}
}
- 编写Dao接口
@Repository
public interface RoleRepository extends JpaRepository<Role,Long> {Role findRoleById(Long id);Role findRoleByName(String name);}
- 测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class JPATest {@Autowiredprivate RoleRepository roleRepository;@Testpublic void testFindById(){Role role = roleRepository.findRoleById(2L);System.out.println(role);}@Testpublic void testFindByName(){Role role = roleRepository.findRoleByName("人事管理");System.out.println(role);}
}
SpringBoot统一异常处理
SpringBoot为何需要统一异常处理
在 Java EE 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过 程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。 每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。 那么将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能较单一, 也实现了异常信息的统一处理和维护
统一异常处理在之前SSM框架中的处理方式回顾
Spring MVC 处理异常有 3 种方式:
(1)使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver;
(2)实现 Spring 的异常处理接口 HandlerExceptionResolver 自定义自己的异常处理器;
(3)使用@ExceptionHandler 注解实现异常处理;
回顾方式一:
SecurityException自定义异常类:
public class SecurityException extends Exception {public SecurityException() { super(); } public SecurityException(String message){super(message);}}
springmvc.xml中的配置全局异常处理器:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<property name="defaultErrorView" value="commons/error" />
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为 exception -->
<property name="exceptionAttribute" value="ex" />
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为 key,异常也页名作为值 --> <property name="exceptionMappings"><value> cn.wolfcode.web.exception.SecurityException=commons/nopermission
<!-- 这里还可以继续扩展不同异常类型的异常处理 --></value></property>
</bean>
回顾方式二:
CustomException自定义异常类:
/**** 系统自定义异常类*/
public class CustomException extends Exception {//异常信息public String message;public CustomException(String message){super(message);this.message = message;}@Overridepublic String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
全局异常处理器:
/*** * 全局异常处理器*/
public class CustomExceptionResolver implements HandlerExceptionResolver{/*** 系统抛出的异常* @param httpServletRequest* @param httpServletResponse* @param o* @param e 系统抛出的异常* @return*/@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {// 解析出异常类型CustomException customException = null;// 若该异常类型是系统自定义的异常,直接取出异常信息在错误页面展示即可。if(e instanceof CustomException){customException = (CustomException)e;}else{// 如果不是系统自定义异常,构造一个系统自定义的异常类型,信息为“未知错误”customException = new CustomException("未知错误");}//错误信息String message = customException.getMessage();ModelAndView modelAndView = new ModelAndView();//将错误信息传到页面modelAndView.addObject("message",message);//指向错误页面modelAndView.setViewName("error");return modelAndView;}
}
错误页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>失败!</title>
</head>
<body>
${message}
</body>
</html>
springmvc.xml中的配置全局异常处理器:
<!--全局异常处理器只要类实现了HandlerExceptionResolver接口,就是一个全局异常处理器哦--><bean class="com.alex.ssm.exception.CustomExceptionResolver"/>
回顾方式三:
@ControllerAdvice
通过使用@ControllerAdvice定义统一的异常处理类,而不是在每个Controller中逐个定义。@ExceptionHandler用来定义函数针对的异常类型。
�ErrorControllerAdvice:
@ControllerAdvice
public class ErrorControllerAdvice {@ExceptionHandler(Exception.class)public String error(Model model, Exception e){model.addAttribute("error",e.getMessage());return "error";}
}
error.ftl:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>${error}
</body>
</html>
在SpringBoot中如何统一异常处理
方式一:
通过使用@ControllerAdvice定义统一的异常处理类,而不是在每个Controller中逐个定义。@ExceptionHandler用来定义函数针对的异常类型。
ErrControllerAdvice:
@ControllerAdvice
public class ErrControllerAdvice {@ExceptionHandlerpublic String error(Exception e , Model model){model.addAttribute("error",e.getMessage());return "error";}
}
注意:如果项目中报错,会被上述异常进行拦截。上述方法,它会拦截到异常,并把异常信息存入model中,然后跳转error的页面,这个页面需要自己编写,在templates模版文件夹中。
error.ftl:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title>
</head>
<body>我是通过注解ControllerAdvice进来的错误页面error : ${error}
</body>
</html>
利用统一异常的处理类,我们可以自定义自己的异常,比如,自定义异常,返回json格式的数据。
第一步:自定义异常类
public class MyCustomException extends RuntimeException {public MyCustomException(String message) {super(message);}public MyCustomException(Throwable cause) {super(cause);}
}
第二步:在异常的处理类中添加自定义异常的拦截方法
@ExceptionHandler@ResponseBodypublic JSONResult customException(MyCustomException e) {JSONResult jsonResult = new JSONResult();jsonResult.setMark(e.getMessage());return jsonResult;}
第三步:在service层添加异常的处理(try...catch(自定义异常))
@Service
public class ExceptionServiceImpl {public void exception() {try {int i = 1 / 0;}catch (Exception e){throw new MyCustomException(e.getMessage());}}
}
第四步: 编写对应的controller,在方法中,调用service中的方法。
@RequestMapping("/ex")@ResponseBodypublic JSONResult list2(){ExceptionServiceImpl service = new ExceptionServiceImpl();service.exception();return new JSONResult();}
方式二:
1,SpringBoot默认情况下,把所有错误都重新定位到/error这个处理路径上,由BasicErrorController类完成处理;
2,SpringBoot提供了默认的替换错误页面的路径:
1,静态错误页面默认结构:
src/resources/public/error/404.html401.html5xx.html�
2,也可以使用模板页面:
src/resources/templates/error/5xx.ftl
该路径方式是通过ErrorMvcAutoConfiguration中的DefaultErrorViewResolver完成的;

喜欢的朋友记得点赞、收藏、关注哦!!!
相关文章:

SpringBoot两天
SpringBoot讲义 什么是SpringBoot? Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式…...

基于Java Springboot诗词学习APP且微信小程序
一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse微信开…...

3.建立本地仓库及常用命令
1.建立本地仓库 要使用Git对我们的代码进行版本控制,首先需要获得本地仓库 1)在电脑的任意位置创建一个空目录,作为我们的本地Git仓库 2)进入这个目录,右键点击Git Bash 窗口 3)执行命令git init 4) 如果创…...

【Linux——实现一个简易shell】
黑暗中的我们都没有说话,你只想回家,不想你回家............................................................... 文章目录 前言 一、【shell工作过程】 二、【命令行参数】 2.1、【获取命令行参数】 1、【输出命令行提示符】 2、【输入命令行参数】 2…...

python使用python-docx处理word
文章目录 一、python-docx简介二、基本使用1、新建与保存word2、写入Word(1)打开文档(2)添加标题(3)添加段落(4)添加文字块(5)添加图片(6…...

Typora设置自动上传图片到图床
Typora设置自动上传图片到图床 方法一:使用php 打开设置界面: 自定义命令: php F:/WWW/php-library/TyporaUploadImage.php ${filename}php代码: # TyporaUploadImage.php <?php // Set the API endpoint URL // $apiUrl…...

如何进行Appium实现移动端UI自动化测试呢?
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 Appium是一个开源跨平台移动应用自动化测试框架。 既然只是想学习下Appium如何入门,那么我们就直奔主题。文章结构如下: 为什么要使用…...

PHP语法学习(第三天)
老规矩,先回顾一下昨天学习的内容 PHP语法学习(第二天) 主要学习了PHP变量、变量的作用域、以及参数作用域。 今天由Tom来打开新的篇章 文章目录 echo 和 print 区别PHP echo 语句实例 PHP print 语句实例 PHP 数组创建数组利用array() 函数 数组的类型索引数组关联…...

mac访达打开终端
选择文件夹打开 选中文件夹,然后右键即可: 在当前文件夹打开 在访达的当前文件夹长按option键 左下角出现当前文件夹路径 右键即可打开终端...

游戏引擎学习第30天
仓库: https://gitee.com/mrxiao_com/2d_game 回顾 在这段讨论中,重点是对开发过程中出现的游戏代码进行梳理和进一步优化的过程。 工作回顾:在第30天,回顾了前一天的工作,并提到今天的任务是继续从第29天的代码开始,…...

git将远端库地址加入到本地库中
git将远端库地址加入到本地库中 git remote add test https://test.git其中test表示远端库的名称,url表示远端库的地址,这样添加后在.git/config配置文件中就能够看到新的remote已经被添加,并且通过git remote -v能够看到新添加的远端库...

学习HTML第三十五天
学习文章目录 一.全局属性二..meta 元信息 一.全局属性 常用的全局属性 id 给标签指定唯一标识,注意: id 是不能重复的。 作用:可以让 label 标签与表单控件相关联;也可以与 CSS 、 JavaScript 配合使 用class 给标签指定类名&a…...

MySQL 事务和索引
关于 MySQL 事务特性、 索引特性。 请你简单解释一下 MySQL 事务是什么? 事务是一组数据库操作,这些操作要么全部成功执行,要么全部不执行。它是一个不可分割的工作单元,用于保证数据的一致性和完整性。 请详细阐述一下事务的 AC…...

Matlab学习笔记
Magic Traits 文件读取 fid fopen(fn,rt);out fscanf(fid,spec,inf);fclose(fid);2. 读取数据 fid fopen(fn,rt); out textscan(fid,spec);运算篇 fprintf(" xxx %d",a),当a为数组时,会输出数组数目行,每行是一个元素相关文…...

在1~n中、找出能同时满足用3除余2,用5除余3,用7除余2的所有整数。:JAVA
链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 在1~n中、找出能同时满足用3除余2,用5除余3,用7除余2的所有整数。 输入描述: 输入一行,包含一个正整数n ,n在100000以内 输出描述:…...

《极品飞车》游戏运行是弹窗“msvcp140.dll文件丢失”是如何造成的?“找不到msvcp140.dll文件”怎么解决?教你几招轻松解决
《极品飞车》游戏运行时弹窗“msvcp140.dll文件丢失”问题解析及解决方案 在畅游《极品飞车》这类精彩刺激的电脑游戏时,突然遇到弹窗提示“msvcp140.dll文件丢失”,无疑会让玩家感到头疼。那么,这个问题究竟是如何造成的?又该如…...

IDE如何安装插件实现Go to Definition
项目背景 框架:Cucumber Cypress 语言:Javascript IDE:vscode 需求 项目根目录cypress-automation的cypress/integration是测试用例的存放路径,按照不同模块不同功能创建了很多子目录,cucumber测试用例.feature文…...

【Vulkan入门】01-列举物理设备
目录 先叨叨git信息主要逻辑VulkanEnvEnumeratePhysicalDevices()PrintPhysicalDevices() 编译并运行程序 先叨叨 上一篇已经创建了VkInstance,本篇我们问问VkInstance,在当前平台上有多少个支持Vulkan的物理设备。 git信息 repository: https://gite…...

pytest(二)excel数据驱动
一、excel数据驱动 excel文件内容 excel数据驱动使用方法 import openpyxl import pytestdef get_excel():excel_obj openpyxl.load_workbook("../pytest结合数据驱动-excel/data.xlsx")sheet_obj excel_obj["Sheet1"]values sheet_obj.valuescase_li…...

主动安全和驾驶辅助模块(ASDM):未来驾驶的核心科技 随着汽车技术的不断进步,驾驶体验和安全性正经历着前所未有的变革。
未来驾驶的核心科技 随着汽车技术的不断进步,驾驶体验和安全性正经历着前所未有的变革。在这场变革中,主动安全和驾驶辅助模块(ASDM)扮演着至关重要的角色。本文将深入探讨ASDM模块的定义、功能、工作原理以及它如何改变我们的驾驶…...

8 Bellman Ford算法SPFA
图论 —— 最短路 —— Bellman-Ford 算法与 SPFA_通信网理论基础 分别使用bellman-ford算法和dijkstra算法的应用-CSDN博客 图解Bellman-Ford计算过程以及正确性证明 - 知乎 (zhihu.com) 语雀版本 1 概念 **适用场景:**单源点,可以有负边࿰…...

Oracle篇—11gRAC安装在linux7之后集群init.ohasd进程启动不了报错CRS-0715问题
💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️…...

[golang][MAC]Go环境搭建+VsCode配置
一、go环境搭建 1.1 安装SDK 1、下载go官方SDK 官方:go 官方地址 中文:go 中文社区 根据你的设备下载对应的安装包: 2、打开压缩包,根据引导一路下一步安装。 3、检测安装是否完成打开终端,输入: go ve…...

【乐企文件生成工程】搭建docker环境,使用docker部署工程
1、自行下载docker 2、自行下载docker-compose 3、编写Dockerfile文件 # 使用官方的 OpenJDK 8 镜像 FROM openjdk:8-jdk-alpine# 设置工作目录 WORKDIR ./app# 复制 JAR 文件到容器 COPY ../lq-invoice/target/lq-invoice.jar app.jar # 暴露应用程序监听的端口 EXPOSE 1001…...
关于数据库数据国际化方案
方案一:每个表设计一个翻译表 数据库国际化的应用场景用到的比较少,主要用于对数据库的具体数据进行翻译,在需要有大量数据翻译的场景下使用,举个例子来说,力扣题目的中英文切换。参考方案可见: https://b…...

【目标跟踪】Anti-UAV数据集详细介绍
Anti-UAV数据集是在2021年公开的专用于无人机跟踪的数据集,该数据集采用RGB-T图像对的形式来克服单个类型视频的缺点,包含了318个视频对,并提出了相应的评估标准(the state accurancy, SA)。 文章链接:https://arxiv.…...

第10章 大模型的有害性(下)
在本章中,我们继续探讨大型语言模型(LLM)可能带来的有害影响,重点讨论有毒性(toxicity)和虚假信息(disinformation)。这些影响不仅影响用户的体验,也可能对社会产生深远的…...

DevOps工程技术价值流:GitLab源码管理与提交流水线实践
在当今快速迭代的软件开发环境中,DevOps(开发运维一体化)已经成为提升软件交付效率和质量的关键。而GitLab,作为一个全面的开源DevOps平台,不仅提供了强大的版本控制功能,还集成了持续集成/持续交付(CI/CD)…...

Qt 面试题学习11_2024-11-29
Qt 面试题 1、什么是Qt事件循环 ?2、纯虚函数和普通的虚函数有什么区别3、Qt 的样式表是什么? 1、什么是Qt事件循环 ? Qt事件循环是一种程序架构,它用于处理窗口系统和其他用户界面事件,以及与用户界面无关的事件例如…...

云原生和数据库哪个好一些?
云原生和数据库哪个好一些?云原生和数据库各有其独特的优势,适用于不同的场景。云原生强调高效资源利用、快速开发部署和高可伸缩性,适合需要高度灵活性和快速迭代的应用。而数据库则注重数据一致性、共享和独立性,确保数据的稳定…...

baomidou Mabatis plus引入异常
1 主要异常信息 Error creating bean with name dataSource 但是有个重要提示 dynamic-datasource Please check the setting of primary 解决方法:增加 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-sp…...

Oracle篇—通过官网下载最新的数据库软件或者历史数据库软件
💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️…...

初学git报错处理 | 从IDEA远程拉取、创建分支中“clone failed”“couldn‘t checkout”
1.远程拉取“clone failed” 我新建了一个文件夹,结果clone failed。后来发现,原来是在这个文件夹里没有建立本地仓库。 打开文件夹,右键git bush,然后键入git init,就可以成果clone啦! 2.新建分支“couldnt checkou…...

【趣味】斗破苍穹修炼文字游戏HTML,CSS,JS
目录 图片展示 游戏功能 扩展功能 完整代码 实现一个简单的斗破苍穹修炼文字游戏,你可以使用HTML、CSS和JavaScript结合来构建游戏的界面和逻辑。以下是一个简化版的游戏框架示例,其中包含玩家修炼的过程、增加修炼进度和显示经验值的基本功能。 图片…...

Luban数据插件的用法
配置后数据后,点击图1中的gen.bat文件启动生成配置数据和解析配置数据代码的程序,自动生成配置数据和解析用到的代码;因为我已经 指定了生成内容的输出路径为Unity项目的路径下面,所以,不用再搬运生成的内容到项目目录…...

「Mac畅玩鸿蒙与硬件35」UI互动应用篇12 - 简易日历
本篇将带你实现一个简易日历应用,显示当前月份的日期,并支持选择特定日期的功能。用户可以通过点击日期高亮选中,还可以切换上下月份,体验动态界面的交互效果。 关键词 UI互动应用简易日历动态界面状态管理用户交互 一、功能说明…...

BiGRU:双向门控循环单元在序列处理中的深度探索
一、引言 在当今的人工智能领域,序列数据的处理是一个极为重要的任务,涵盖了自然语言处理、语音识别、时间序列分析等多个关键领域。循环神经网络(RNN)及其衍生结构在处理序列数据方面发挥了重要作用。然而,传统的 RN…...

sscanf与sprintf函数
本期介绍🍖 主要介绍:sscanf()、sprintf()这对输入/输出函数,并详细讲解了这两个函数的应用场景。 概述🍖 在C语言的输出和输入库中,有三对及其相似的库函数:printf()、scanf()、fprintf()、fscanf()、spri…...

工业智能网关在该企业中的应用实践
随着工业4.0时代的到来,智能制造已成为企业转型升级的重要方向。工业智能网关作为工业互联网架构中的关键组件,正逐步在各大企业中发挥重要作用。本文将以某制造企业为例,详细探讨天拓四方工业智能网关在该企业中的应用实践,展现其…...

python毕业设计常见的一些开源库!
作为一个Python开发者,在开发过程中经常会使用到各种工具库来简化工作、提高效率。以下是一些常见的Python开发工具库及其介绍和官方链接。 序号库名称功能介绍官方链接或参考网址1numpy提供高效的多维数组操作和数学函数,是许多数据科学和科学计算任务的…...

编程语言中什么是框架?什么是Cocoa?Foundation.framework的底层实现?Swift如何引入ObjC框架?
编程语言中什么是框架? 在编程语言中,框架(Framework)是一种特定的软件库,它提供了一套预先定义的代码和组件,用于加速和简化特定类型的应用程序的开发。框架通常提供了一套标准化的开发工具集和约定&#…...

C++ 游戏开发入门
一、为什么选择 C 进行游戏开发 C 在游戏开发领域具有独特的地位。它兼具高效性与对底层硬件的良好控制能力,这使得它非常适合开发对性能要求极高的游戏核心引擎部分。许多知名的大型游戏,如《使命召唤》系列、《虚幻竞技场》等,其底层架构都…...

【娱乐项目】基于cnchar库与JavaScript的汉字查询工具
Demo介绍 利用了 cnchar 库来进行汉字相关的信息查询,并展示了汉字的拼音、笔画数、笔画顺序、笔画动画等信息用户输入一个汉字后,点击查询按钮,页面会展示该汉字的拼音、笔画数、笔画顺序,并绘制相应的笔画动画和测试图案 cnchar…...

20241129解决在Ubuntu20.04下编译中科创达的CM6125的Android10出现找不到库文件libncurses.so.5的问题
20241129解决在Ubuntu20.04下编译中科创达的CM6125的Android10出现找不到库文件libncurses.so.5的问题 2024/11/29 21:11 缘起:中科创达的高通CM6125开发板的Android10的编译环境需要。 vendor/qcom/proprietary/commonsys/securemsm/seccamera/service/jni/jni_if.…...

自然语言处理:基于BERT预训练模型的中文命名实体识别(使用PyTorch)
命名实体识别(NER) 命名实体识别(Named Entity Recognition, NER)是自然语言处理(NLP)中的一个关键任务,其目标是从文本中识别出具有特定意义的实体,并将其分类到预定义的类别中。这…...

记录一次 用php 调用ai用stream返回
直接写代码了 config 里面是配置文件就不写了,这样要去不同的平台申请去 写一个 service,解释一下代码 写了两个ai,一个是星火,一个是质谱,他们都是调用curl 方法,并返回数据, s t r e a m 为假就是等等返…...

vue引入并调用electron插件在网页报错Dynamic require of “electron“ is not supported
报错信息 Error: Dynamic require of "electron" is not supported 这个错误信息表明你正在尝试在一个普通的网页环境中动态地引入(electron),但是这是不被允许的。Electron是一个用于构建桌面应用程序的框架,它结合了Node.js和Chromium&#…...

【C++】数组
1.概述 所谓数组,就是一个集合,该集合里面存放了相同类型的数据元素。 数组特点: (1)数组中的每个数据元素都是相同的数据类型。 (2)数组是有连续的内存空间组成的。 2、一维数组 2.1维数组定…...

Python 中的 try-except 语句介绍
Python 中的 try-except 语句介绍 在编程过程中,异常处理是非常重要的一部分。Python 提供了 try-except 语句来捕获和处理程序运行时可能出现的异常。本文将详细介绍 try-except 语句的基本概念、常见错误类型以及一些实用的代码示例。 1. try-except 语句的基本…...

网络原理-初识
1.网络的发展历程 独立模式 独立模式:计算机之间相互独立。 每个终端A、B、C各自持有客户端数据 网络互连 随着时代的发展,越来越需要计算机之间互相通信,共享软件和数据,即可以多个计算机协调工作来完成业务,就有…...