SpringBoot2核心技术最好的一篇文章——1.基础入门
SpringBoot核心技术 基础入门
- 一、Spring与SpringBoot
- 1.1 SpringBoot的优点
- 1.2 SpringBoot缺点
- 1.3 详细讲解请观看尚硅谷雷神
- 二、SpringBoot2入门
- 2.1 Maven设置
- 2.2 HelloSeven
- 2.3 创建主程序
- 2.4 编写业务
- 2.5 测试
- 2.6 简化配置
- 2.7 简化部署
- 三、了解自动配置管理
- 3.1 依赖管理
- 3.2 自动配置
- 3.3 容器功能
- 3.3.1组件添加
- ⭐1. @Configuration
- ⭐2. @Bean、@Component、@Controller、@Service、@Repository
- ⭐3. @ComponentScan、 @Import
- ⭐4. @Conditional
- 3.3.2 原生配置文件引入
- ⭐ 1. @ImportResource
- ⭐ 2. 配置绑定 @ConfigurationProperties
- ⭐第一种方式 @ConfigurationProperties(prefix = "cat2") + @Component()
- ⭐第二种方式 @ConfigurationProperties(prefix = "cat2") + @EnableConfigurationProperties
- 3.4 自动配置原理入门
- 3.4.1 引导加载自动配置类
- ⭐ 1. @SpringBootConfiguration
- ⭐ 2.@ComponentScan("com.jzq")
- ⭐ 3. @EnableAutoConfiguration
- 3.4.2 按需开启自动配置项
- 3.4.3 定制化修改自动配置
- 3.4.4最佳实践
- 3.4.5 实用技巧
本笔记源于观看尚硅谷教学视频,地址:尚硅谷视频
一、Spring与SpringBoot
1.1 SpringBoot的优点
1.2 SpringBoot缺点
1.3 详细讲解请观看尚硅谷雷神
地址:雷神讲解
二、SpringBoot2入门
2.1 Maven设置
<mirrors><mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</url></mirror></mirrors><profiles><profile><id>jdk-1.8</id><activation><activeByDefault>true</activeByDefault><jdk>1.8</jdk></activation><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion></properties></profile></profiles>
2.2 HelloSeven
需求: 浏览器发送/hello请求, 响应Hello, SpringBoot2
2.3 创建主程序
@SpringBootApplication : 这是一个SpringBoot应用.(@SpringBootApplication(scanBasePackages = “com.jzq.boot”))
等同于 =>
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.jzq.boot”)
package com.jzq.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*主程序类@SpringBootApplication : 这是一个SpringBoot应用*/@SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}
}
2.4 编写业务
package com.jzq.boot.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;//@ResponseBody
//@Controller@RestController
public class HelloController {@RequestMapping("/hello")public String handle01(){return "hello seven2";}
}
2.5 测试
直接运行MainApplication的Main方法就行!
2.6 简化配置
在资源包创建 application.properties进行配置,例如配置端口号:
server.port=8564
2.7 简化部署
在pom文件加入如下配置,点击Maven的Lifecycle下的clean再点击package。
直接打包为jar包,在控制台运行即可!
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
⭐ 可能会遇到的问题: 取消掉cmd控制台的快速编译模式!
三、了解自动配置管理
3.1 依赖管理
- ⭐父项目做依赖管理
<--/ 依赖管理 -->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version>
</parent><--/ 它的父项目 -->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.5.6</version>
</parent>
<--/ 几乎声明了所有开发中常用的依赖版本号 --->
- ⭐开发导入starter场景启动器
- 见到很多spring-boot-starter-*: * 表示某种场景 例如: aop
- 只要引入 starter,这个场景的所有常规需要的依赖我们都自动引入
- SpringBoot所有支持的场景: https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
- 见到 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
- 所有场景最底层的依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
- ⭐无需关注版本号,自动版本仲裁
- 引入依赖默认都可以不写版本。
- 引入非版本仲裁的jar或者自己需要指定的版本的jar,要写版本号。
- ⭐可以修改版本号
- 查看spring-boot-dependencies里面规定的当前依赖的版本号,用key例如:<version>${activemq.version}
- 在当前项目的pom的 <properties>上写自己需要的项目版本!
<properties><mysql.version>5.1.43</mysql.version>
</properties><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>
3.2 自动配置
- ⭐自动配置好Tomcat
- 引入了tomcat的依赖
- ⭐自动配置好了SpringMVC
- ⭐自动配置了Web常见功能,如:字符编码问题
-⭐ 默认的包结构- 自动扫扫描主函数所在以及主函数下面的包
- 如果自己配置则应该修改主函数的注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.jzq”)
等同于↓↓↓
@SpringBootApplication(scanBasePackages = “com.jzq”)package com.jzq.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan;/*主程序类@SpringBootApplication : 这是一个SpringBoot应用*///@SpringBootApplication(scanBasePackages = "com.jzq")@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.jzq") public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);} }
- ⭐各种配置拥有默认值
- 默认配置最终都是映射到MultipartProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
- ⭐按需加载所有自动配置项
- 非常多的starter
- 引入了哪些场景这个场景的自动配置才会开启
- SpringBoot所有的自动配置功能都在: spring-boot-starter-web依赖的spring-boot-starter中
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>2.5.6</version><scope>compile</scope> </dependency>
3.3 容器功能
3.3.1组件添加
⭐1. @Configuration
- 基本使用
- Full模式与Lite模式
- 示例
- 最佳实战
- ⭐ 配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断。(Lite(proxyBeanMethods: false))
- ⭐ 配置类组件之间有依赖关系用Full模式,方法被会调用得到之前单实例组件。可以很方便的进行组件依赖。(Full(proxyBeanMethods: true))
⭐配置类代码:
@Configuration(proxyBeanMethods = true) : // 告诉SpringBoot这是一个配置类 == 配置文件.
配置类本身也是组件.
⭐@Bean : // 给容器中添加组件,以方法名作为组件的id,返回值就是组件类型,返回的值就是组件在容器中的实例.
假如 @Bean(“cat777”), 指定组件名为"cat777"
@Bean
public User user01() {…}
package com.jzq.boot.config;import com.jzq.boot.bean.Cat;
import com.jzq.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*
* 1. 配置类里面使用的@Bean标注在方法上给容器注册组件,默认也是单实例的
* 2. 配置类本身也是组件
* 3. proxyBeanMethods: 代理bean的方法
* Full(proxyBeanMethods: true)
* Lite(proxyBeanMethods: false)*/@Configuration(proxyBeanMethods = true) // 告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {@Bean // 给容器中添加组件,以方法名作为组件的id,返回值就是组件类型,返回的值就是组件在容器中的实例public User user01() {User wxq = new User("wxq");wxq.setCat(cat01());return wxq;}@Bean("catttt")public Cat cat01() {return new Cat(11);}
}
⭐2. @Bean、@Component、@Controller、@Service、@Repository
Spring框架介绍了
AOP的注解
⭐3. @ComponentScan、 @Import
@ComponentScan: 包扫描注解
@Import({User.class, DBHelper.class}) 给容器中自动场创建这两个类型的组件,默认组件的名字就是全类名
package com.jzq.boot.config;import ch.qos.logback.core.db.DBHelper;
import com.jzq.boot.bean.Cat;
import com.jzq.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true) // 告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {public User user01() {User wxq = new User("wxq");wxq.setCat(cat01());return wxq;}@Bean("catttt")public Cat cat01() {return new Cat(11);}
}
测试代码与测试图如下:
// 6. 测试@Import()
String[] beanNamesForType = run.getBeanNamesForType(User.class);
System.out.println("s7da7d7sa7das7");
for (String s : beanNamesForType) {System.out.println(s);
}
DBHelper bean2 = run.getBean(DBHelper.class);System.out.println(bean2);
⭐4. @Conditional
条件装配:满足Condittional指定的条件,则进行组件注入
⭐通过@ConditionalOnBean(name = “catttt”)来指定是否装配,因为该bean装载依赖于另一个bean,假如依赖的catttt没有被转载,该方法也不自动装载;当该方法有catttt时就自动装配。
⭐切记装配顺序,catttt这个组件要在上面!!!
⭐ 当条件装配注解声明在方法上,当条件成立后方法内的配置生效;当注解声明在类上,当条件成立后,类下面的配置才会生效。
⭐ @ConditionalOnMissingBean(name=“seven”)
恰恰相反,当容器有seven时不装配,没有seven时才会装配!
package com.jzq.boot.config;import ch.qos.logback.core.db.DBHelper;
import com.jzq.boot.bean.Cat;
import com.jzq.boot.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;@Import({User.class, DBHelper.class})
@Configuration() // 告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {@Bean("catttt")public Cat cat01() {return new Cat(11);}@ConditionalOnBean(name = "catttt")@Bean // 给容器中添加组件,以方法名作为组件的id,返回值就是组件类型,返回的值就是组件在容器中的实例public User user01() {User wxq = new User("wxq");wxq.setCat(cat01());return wxq;}
}
⭐通过这个 run.containsBean(“user01”); 测试是否装配了
Boolean c1 = run.containsBean("catttt");
System.out.println(c1);Boolean u1 = run.containsBean("user01");
System.out.println(u1);
3.3.2 原生配置文件引入
⭐ 1. @ImportResource
@ImportResource(“classpath:bean.xml”): 导入Spring的配置文件,spring通过xml配置的bean也会加载到容器,不导入,不会加载。此注解声明在主配置类。
xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user11" class="com.jzq.boot.bean.User"><property name="name" value="dasdsda"></property></bean>
</beans>
主配置类:
package com.jzq.boot.config;import ch.qos.logback.core.db.DBHelper;
import com.jzq.boot.bean.Cat;
import com.jzq.boot.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;/*
* 5. @ImportResource("classpath:bean.xml"): 导入Spring的配置文件*/@Import({User.class, DBHelper.class})
@Configuration() // 告诉SpringBoot这是一个配置类 == 配置文件
@ImportResource("classpath:bean.xml")
public class MyConfig {@Bean("catttt")public Cat cat01() {return new Cat(11);}@ConditionalOnBean(name = "catttt")@Bean // 给容器中添加组件,以方法名作为组件的id,返回值就是组件类型,返回的值就是组件在容器中的实例public User user01() {User wxq = new User("wxq");wxq.setCat(cat01());return wxq;}}
⭐ 2. 配置绑定 @ConfigurationProperties
使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时可以使用。
⭐第一种方式 @ConfigurationProperties(prefix = “cat2”) + @Component()
@Component()通过注解的方式注册bean
@ConfigurationProperties(prefix = “cat2”): 配置绑定properties里的cat2.* 的数据
package com.jzq.boot.bean;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component(value = "cat")
@ConfigurationProperties(prefix = "cat2")
public class Cat {private int age;private String name;public Cat() {}public Cat(int age) {this.age = age;}public Cat(int age, String name) {this.age = age;this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
注意 cat2的变量名要和Bean类的成员属性名字一样
server.port=8564
cat2.name="sdsda"
cat2.age=18
测试
@AutowiredCat cat;@RequestMapping("/cat")public Cat car() {return cat;}
⭐第二种方式 @ConfigurationProperties(prefix = “cat2”) + @EnableConfigurationProperties
@ConfigurationProperties(prefix = “cat2”) :注解在实体类
@EnableConfigurationProperties:注解在主配置类
package com.jzq.boot.bean;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;//@Component(value = "cat")
@ConfigurationProperties(prefix = "cat2")
public class Cat {private int age;private String name;public Cat() {}public Cat(int age) {this.age = age;}public Cat(int age, String name) {this.age = age;this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
@EnableConfigurationProperties: 注解在配置类
package com.jzq.boot.config;import ch.qos.logback.core.db.DBHelper;
import com.jzq.boot.bean.Cat;
import com.jzq.boot.bean.User;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;/*
* 1. 配置类里面使用的@Bean标注在方法上给容器注册组件,默认也是单实例的
* 2. 配置类本身也是组件
* 3. proxyBeanMethods: 代理bean的方法
* Full(proxyBeanMethods: true)
* Lite(proxyBeanMethods: false)
* 4. @Import({User.class, DBHelper.class})
* 给容器中自动场创建这两个类型的组件,默认组件的名字就是全类名
*
* 5. @ImportResource("classpath:bean.xml"): 导入Spring的配置文件*/@Import({User.class, DBHelper.class})
@Configuration() // 告诉SpringBoot这是一个配置类 == 配置文件
@ImportResource("classpath:bean.xml")
@EnableConfigurationProperties
public class MyConfig {@Bean()public Cat cat01() {return new Cat(11);}//@ConditionalOnBean(name = "catttt")@Bean // 给容器中添加组件,以方法名作为组件的id,返回值就是组件类型,返回的值就是组件在容器中的实例public User user01() {User wxq = new User("wxq");wxq.setCat(cat01());return wxq;}}
3.4 自动配置原理入门
⭐在spring-boot-autoconfigure-2.5.6.jar 查看
3.4.1 引导加载自动配置类
⭐ 1. @SpringBootConfiguration
@Configuration: 代表当前是一个配置类。
⭐ 2.@ComponentScan(“com.jzq”)
指定扫描哪些,Spring注解。
⭐ 3. @EnableAutoConfiguration
由
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
组成
- @AutoConfigurationPackage
利用Registrar给容器中导入一系列组件
将指定的一个包下的所有组件导入进来?默认时MainApplication
@Import({Registrar.class})public @interface AutoConfigurationPackage {...}
- @Import({AutoConfigurationImportSelector.class})
1 利用getAutoConfigurationEntry(annotationMetadata); 给容器中批量导入一些组件;
2 调用List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取到所有需要导入到容器的组件。
利用工厂加载
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {}
4 从META-INF/spring.factories位置加载一个文件
默认扫描我们当前系统里面的所有META-INF/spring.factories
spring-boot-autoconfigure-2.5.6.jar内也有META-INF/spring.factories
如:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener...# Depends on database initialization detectors
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
org.springframework.boot.autoconfigure.batch.JobRepositoryDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.quartz.SchedulerDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.session.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector
3.4.2 按需开启自动配置项
虽然我们的127个场景的所有自动配置启动的时候会默认全部加载。
但是按照条件装配规则,最终会按需配置。
3.4.3 定制化修改自动配置
SpringBoot 默认会在底层配置好所有德组件,但是如果用户自己配置了以用户配置的优先
⭐总结:
SpringBoot先加载所有的自动配置类。
每个自动配置类按照条件进行生效。默认都会绑定配置文件指定的值,xxxxProperties里面拿,xxxxProperties和配置文件进行了绑定。
生效的配置类就会给容器中装配很多组件。
只要容器中有这些组件,相当于这些功能就有了。
只要用户有自己的配置,就以用户的优先。
- 用户直接自己的@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改。
xxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties
⭐⭐如何自己修改配置步骤
第一种就是看官方文档
⭐⭐第二钟步骤:
- 我找到spring-boot-autoconfigure-2.5.6.jar
2.查看@EnableConfigurationProperties({CacheProperties.class})
- 看注解@ConfigurationProperties(prefix = “spring.cache”)里面的值
- 在application.properties内修改配置
3.4.4最佳实践
- 引入场景依赖
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
- 查看自动配置了哪些
自己分析,引入场景对应的自动配置一般都生效了。
配置文件中的debug=true开启自动配置报告,Negative(不生效)、Positive(生效)
- 是否需要修改
参照文档修改配置项:
https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.core
或者自己分析。 xxxProperties绑定的配置文件有哪些。
自定义加入或者替换组件:
@Bean、@Component…
自定义器: xxxxCustomizer;
3.4.5 实用技巧
- dev-tools
配置pom,按ctrl+f9重新部署
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional>
</dependency>
- Spring Initailizr(项目初始化向导)
使用步骤:
最后生成的文件目录结构:
SpringBoot2核心技术最好的一篇文章——1.基础入门相关推荐
- SpringBoot2核心技术最好的一篇文章——2. 核心技术
SpringBoot2核心技术最好的一篇文章--2.核心技术 一.配置文件 1.1 properties 1.2 yaml 1. 简介 2. 基本语法 3. 数据类型 1.3 配置处理器 二. web ...
- 学Android移动开发 第1章 Android基础入门
文章目录 1.1 Android简介 什么是Android Android和iOS主要区别 1.1.1 通信技术 1.1.2 Android起源 1.1.3 Android体系结构 1.1.4 Dal ...
- 一篇文章带你入门adb自动化测试
一篇文章带你入门adb自动化测试 前言 一.什么是adb 1.adb的原理的应用场景 2.(adb)Android debug bridge用于调试使用安卓系统的设备 3.adb基本原理 二.adb环 ...
- 转发 微博 Qzone 微信 一篇文章带你入门ZooKeeper实现原理!(超详细)
转发 微博 Qzone 微信 一篇文章带你入门ZooKeeper实现原理!(超详细)
- 自动驾驶的核心技术是什么----一篇文章带你揭开自动驾驶的神秘面纱
1.自动驾驶发展历史 早在1925年,世界上就诞生了第一辆自动驾驶汽车,不过,依照我们当下的技术水准来看,那时的自动驾驶,或者只是在炒概念. 因为当时的自动驾驶,就是驾驶员通过无线电操控汽车,什么意思 ...
- python基础论文_北大博士Python学习笔记,Python基础语法总结,一篇文章带你入门...
image.png 网上现在Python学习资料有很多,但是很杂.很多初学Python的朋友就不知道该怎么去抉择,那些是自己当下所需要的. 刚好朋友是北大的博士,在IT行业也工作八年了.就把他学习Py ...
- 0基础学python培训班_[长文] 学Python不用培训班,一篇文章带你入门
最近有许多小伙伴后台联系我,说目前想要学习Python,但是没有一份很好的资料入门.一方面的确现在市面上Python的资料过多,导致新手会不知如何选择,另一个问题很多资料内容也很杂,从1+1到深度学习 ...
- 一篇文章带你入门音视频
一.概述 1)流媒体协议是服务器与客户端之间通信遵循的规定.当前网络上主要的流媒体协议如表所示. 2)封装格式的主要作用是把视频码流和音频码流按照一定的格式存储在一个文件中. 3)视频编码的主要作用是 ...
- 有没有python的班_【万字长文】别再报班了,一篇文章带你入门Python
最近有许多小伙伴后台联系我,说目前想要学习Python,但是没有一份很好的资料入门.一方面的确现在市面上Python的资料过多,导致新手会不知如何选择,另一个问题很多资料内容也很杂,从1+1到深度学习 ...
最新文章
- 清结算系统的一些思考
- 你用过这种奇葩的C#注释吗?如何看待
- Ubuntu 14.04 安装SSH
- 基于jsf的项目_JSF基于事件的交流:新派方法
- breakcontinue
- python判断进程是否存在
- kali rpm 安装方法_linux下制作安装rpm包的方法
- centOS 自动锁屏 解决办法
- LabVIEW状态机小灯按顺序点亮条件结构+自定义枚举
- java打开android_解决android studio 打开java文件 内容全变了的问题
- python2.7.10 VS2015编译方法
- 我的Android进阶之旅------gt;Android嵌入图像InsetDrawable的使用方法
- python 使用函数参数注解
- 实验过程中收获的经验、教训、感想
- Glide 加载圆形图片
- 计算机的英语怎样写,电脑的英文作文怎么写好呢
- 2022年南京大学软件工程专硕上岸经验帖
- java word 在线编辑图片,_卓正软件 - PageOffice官方网站 - 在线编辑Word、Excel的Office文档控件...
- Unity3D的传送带和物体移动
- cocos2d-x apk 打包路径太深