F1V3.0-8 Springboot基本使用及要点
来源:互联网 发布:java 开启gzip压缩 编辑:程序博客网 时间:2024/05/16 05:00
1 SpringBoot简介
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。
该框架使用了特定的方式(继承starter,约定优先于配置)来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
Spring Boot并不是一个框架,从根本上将,它就是一些库的集合,maven或者gradle项目导入相应依赖即可使用Spring Boot,而且无需自行管理这些库的版本。
github地址:https://github.com/spring-projects/spring-boot
Spring Boot默认使用tomcat作为服务器,使用logback提供日志记录。
最根本上来讲,Spring Boot就是一些库的集合,它能够被任意项目的构建系统所使用。简便起见,该框架也提供了命令行界面,它可以用来运行和测试Boot应用。框架的发布版本,包括集成的CLI(命令行界面),可以在Spring仓库中手动下载和安装。一种更为简便的方式是使用Groovy环境管理器(Groovy enVironment Manager,GVM),它会处理Boot版本的安装和管理。Boot及其CLI可以通过GVM的命令行gvm install springboot进行安装。在OS X上安装Boot可以使用Homebrew包管理器。为了完成安装,首先要使用brew tap pivotal/tap切换到Pivotal仓库中,然后执行brew install springboot命令。
要进行打包和分发的工程会依赖于像Maven或Gradle这样的构建系统。为了简化依赖图,Boot的功能是模块化的,通过导入Boot所谓的“starter”模块,可以将许多的依赖添加到工程之中。为了更容易地管理依赖版本和使用默认配置,框架提供了一个parent POM,工程可以继承它
2 Spring Boot基本使用
2.1 构建一个简单的SpringBoot应用
2.1.1构建一个pom文件
Spring Boot提供很多”Starter POMs”, 这能够让你轻松的将jars添加到你的classpath下。 我们的示例程序已经在POM的partent节点使用spring-boot-starter-paren。 spring-boot-starter-parent是一个特殊的starter, 它提供了有用的Maven默认设置。 同时, 它也提供了一个dependency-management 节点,这样对于”blessed“依赖你可以省略version标记。
其他的”Starter POMs“简单的提供依赖, 这些依赖可能是你开发特定类型的应用时需要的。 由于正在开发一个web应用, 我们将添加一个 spring-boot-starter-web 依赖 。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.0.BUILD-SNAPSHOT</version></parent> <!--starter-web提供了内置的Tomcat web服务器和Spring MVC依赖 --><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency></dependencies>
2.1.2 编写一个启动类
为了完成应用程序, 我们需要创建一个单独的Java文件。 Maven默认会编译 src/main/java 下的源码, 所以你需要创建那样的文件结构, 然后添加一个名为 src/main/java/Example.java 的文件:
import org.springframework.boot.*;import org.springframework.boot.autoconfigure.*;import org.springframework.stereotype.*;import org.springframework.web.bind.annotation.*;@RestController@EnableAutoConfigurationpublic class Example { @RequestMapping("/") String home() { return "Hello World!"; } public static void main(String[] args) throws Exception { SpringApplication.run(Example.class, args); }}
尽管这里没有太多代码, 但很多事情正在发生。 让我们分步探讨重要的部分。
① @RestController和@RequestMapping注解
我们的Example类上使用的第一个注解是 @RestController 。 这被称为一个构造型(stereotype) 注解。 它为阅读代码的人们提供建议。对于Spring,该类扮演了一个特殊角色。 在本示例中, 我们的类是一个web @Controller,所以当处理进来的web请求时, Spring会询问它。
@RequestMapping 注解提供路由信息。 它告诉Spring任何来自”/”路径的HTTP请求都应该被映射到 home 方法。 @RestController 注解告诉Spring以字符串的形式渲染结果, 并直接返回给调用者。
② @EnableAutoConfiguration注解
第二个类级别的注解是 @EnableAutoConfiguration 。 这个注解告诉Spring Boot根据添加的jar依赖猜测你想如何配置Spring。由于 spring-boot-starter-web 添加了Tomcat和Spring MVC, 所以auto-configuration将假定你正在开发一个web应用并相应地对Spring进行设置。
③ main方法
main方法通过调用run, 将业务委托给了Spring Boot的SpringApplication类。 SpringApplication将引导我们的应用, 启动Spring, 相应地启动被自动配置的Tomcat web服务器。 我们需要将 Example.class 作为参数传递给run方法来告诉SpringApplication谁是主要的Spring组件。 为了暴露任何的命令行参数, args数组也会被传递过去。
run方法执行顺序:
1.初始化SpringApplicationRunListeners并且开始监听
2.加载StandardEnvironment(包括系统参数 环境变量参数 properties/yml文件 profiles)
3.把environment set到Listeners里面
4.默认通过AnnotationConfigApplicationContext扫描所有的注解类,创建并且注册bean(默认都是创建的单列)
5.创建context,并且把environment set到context里面
备注:如果需要初始化spring-boot即将完成的时候马上去做一些事情,我们可以实现CommandLineRunner该接口
2.1.3 启动Spring-boot
我们可以听过IDE来启动主类程序,也可以通过maven命令的方式启动服务(在项目根目录下输入 mvn spring-boot:run 来启动应用)
如果使用一个浏览器打开localhost:8080, 你应该可以看到以下输出:
hello world
2.2 Starter POMs
starter POMs是可以包含到应用中的一个方便的依赖关系描述符集合。 你可以获取所有Spring及相关技术的一站式服务, 而
不需要翻阅示例代码, 拷贝粘贴大量的依赖描述符。 例如, 如果你想使用Spring和JPA进行数据库访问, 只需要在你的项目中包含 spring-boot-starter-data-jpa 依赖, 然后你就可以开始了。
该starters包含很多你搭建项目, 快速运行所需的依赖, 并提供一致的, 管理的传递依赖集
Spring Boot生产准备的starters
最后, Spring Boot包含一些可用于排除或交换具体技术方面的starters
2.3 SpringBoot常用注解及功能
主类通常位于根包中,可以使用@EnableAutoConfiguration注解你的主类。使用根包允许你使用 @ComponentScan 注解而不需要定义一个 basePackage 属性。 如果main类位于根包中, 你也可以使用 @SpringBootApplication 注解。
Springbooot包结构推介:
2.3.1 Spring Beans和依赖注入
我们经常使用 @ComponentScan 注解搜索beans, 并结合 @Autowired 构造器注入
如果按照上面的结构划分包结构,你可以添加 @ComponentScan 注解而不需要任何参数,也可是自己定义扫描路劲@ComponentScan (basePackages = “xxx.xxx.xxx”),你的所有应用程序组件( @Component , @Service , @Repository , @Controller 等) 将被自动注册为Spring Beans。
2.3.2 @SpringBootApplication
很多Spring Boot开发者总是使用 @Configuration , @EnableAutoConfiguration 和 @ComponentScan 注解他们的main类。 由于这些注解被如此频繁地一块使用,Spring Boot提供一个方便的 @SpringBootApplication 选择。
该 @SpringBootApplication 注解等价于以默认属性使用 @Configuration,@EnableAutoConfiguration 和 @ComponentScan。当需要特殊的包扫描时可以结合 @ComponentScan来配置你的扫描路劲。
2.3.3 @RestController
用于标注控制层组件(如struts中的action),包含@Controller和@ResponseBody。@RestController 注解告诉Spring以字符串的形式渲染结果,并直接返回给调用者
2.3.4 @Configuration
Spring Boot提倡基于Java的配置。尽管你可以使用一个XML源来调用 SpringApplication.run() ,我们通常建议你使用 @Configuration 类作为主要源。一般定义 main 方法的类也是主要 @Configuration 的一个很好候选。你不需要将所有的 @Configuration 放进一个单独的类。 @Import 注解可以用来导入其他配置类。另外,你也可以使用 @ComponentScan 注解自动收集所有的Spring组件,包括 @Configuration 类。
2.3.5 @EntityScan
用于扫描Jpa实体类
2.3.6 @Component和 @Bean
@Component被用在要被自动扫描和装配的类上。@Component类中使用方法或字段时不会使用CGLIB增强(及不使用代理类:调用任何方法,使用任何变量,拿到的是原始对象)Spring 注解@Component等效于@Service,@Controller,@Repository
@Bean主要被用在方法上,来显式声明要用生成的类;用@Configuration注解该类,等价 与XML中配置beans;用@Bean标注方法等价于XML中配置bean。现在项目上,本工程中的类,一般都使用@Component来生成bean。在把通过web service取得的类,生成Bean时,使用@Bean和getter方法来生成bean
2.4属性配置以及读取
spring-boot 属性分为两种:
1.spring-boot默认属性(application.properties或者application.yml 系统属性 环境变量属性)
2.自定义加载属性
spring-boot启动的时候会默认扫描resources目录下面的application.properties或者application.yml,扫瞄结束后会把值放入到Environment。
初始化bean的时候需要用到配置的值,我们可以根据这三种方式去获取:
1).继承EnvironmentAware获取Environment
2).通过注解@value进行填充值
3).注入environment 通过environment获取
@Configuration public class MyProperty implements EnvironmentAware { public void setEnvironment(Environment environment) { //方案一 继承EnvironmentAware 获取yml里面的值 RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "jdbc."); String url = propertyResolver.getProperty("url"); } //方案二 通过注解value进行填充值 @Value("${jdbc.url}") private String url; //方案三 注入environment 通过environment获取 @Autowired private Environment environment; public void init(){ RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "jdbc."); String url = environment.getProperty("url"); } }
2.4.1 自定义配置文件读取
Spring Boot支持自定义属性文件的读取,请看下面的例子:
该例子的核心是:
@PropertySource(value="classpath:/config/custom.properties",ignoreResourceNotFound= true)
// application 注解@Configuration@ComponentScan@EnableAutoConfiguration@PropertySource(value="classpath:/config/custom.properties", ignoreResourceNotFound = true)@Controllerpublic class PropertiesController { @Value("${CONSTANT_PASSWORD}") private String password; @Autowired private ConfigBean configBean; @RequestMapping("/custom") public String custom(@RequestParam(value="name",required=false, defaultValue="${CONSTANT_USER}") String name , Model model) { model.addAttribute("name", name); model.addAttribute("password", password); System.out.println(configBean); return "custom"; } public static void main(String[] args) { SpringApplication.run(PropertiesController.class,args); }}
config/custom.properties
## 常量配置CONSTANT_USER=vergiylnCONSTANT_PASSWORD=中文123## thymeleaf 配置spring.thymeleaf.prefix=classpath:/templates/properties/spring.thymeleaf.suffix=.htmlspring.thymeleaf.mode=HTML5spring.thymeleaf.encoding=UTF-8spring.thymeleaf.content-type=text/html# set to false for hot refreshspring.thymeleaf.cache=false
ConfigBean.properties
vergilyn.map[blog]=http://www.cnblogs.com/VergiLyn/vergilyn.map[name]=VergiLynvergilyn.map[remark]=备注,中文23333vergilyn.list[0]=Carpentersvergilyn.list[1]=Celine Dionvergilyn.list[2]=Bon Jovivergilyn.list[3]=Taylor Swiftvergilyn.str=stringvergilyn.num=124vergilyn.date=2017-01-14 23:55:19vergilyn.isSuccess=false
读取ConfigBean.properties的Java类如下:
@Configuration@ConfigurationProperties(prefix = "vergilyn")// 配置文件中的前缀@PropertySource("classpath:config/ConfigBean.properties")@Componentpublic class ConfigBean implements Serializable{ private String str; private Integer num; private boolean isSuccess; private Map<String, String> map; private List<String> list; public String getStr() { return str; } public void setStr(String str) { this.str = str; } public Integer getNum() { return num; } public void setNum(Integer num) { this.num = num; } public Map<String, String> getMap() { return map; } public void setMap(Map<String, String> map) { this.map = map; } public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } public Boolean isSuccess() { return isSuccess; } public void setIsSuccess(Boolean success) { isSuccess = success; }}
2.4.2 默认配置方式:application.properties
application.properties文件可以放在一下四个位置:
A、jar包所在目录同级的目录“/config”的子目录下;
B、jar包锁在目录的同级目录下;
C、classpath根目录的“/config”包下;
D、classpath的根目录下;
同样,这个列表按照优先级排序,也就是说,src/main/resources/config下application.properties覆盖src/main/resources下application.properties中相同的属性,如图:
相关知识补充
1.A、B适合生产环境,C、D适合开发环境;
2.如果同时存在,则按照A、B、C、D的顺序优先选取;
2.5 spring boot默认提供的常用类
2.5.1 Spring boot数据访问配置
需要引入jpa依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency
这里使用druid连接池,还需要引入druid的依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.25</version> </dependency>
Spring Boot中的application.properties配置信息:
# 驱动配置信息 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.url = jdbc:mysql://127.0.0.1:3306/mealsystem?useUnicode=true&characterEncoding=utf-8 spring.datasource.username = root spring.datasource.password = 123456 spring.datasource.driverClassName = com.mysql.jdbc.Driver #连接池的配置信息 spring.datasource.initialSize=5 spring.datasource.minIdle=5 spring.datasource.maxActive=20 spring.datasource.maxWait=60000 spring.datasource.timeBetweenEvictionRunsMillis=60000 spring.datasource.minEvictableIdleTimeMillis=300000 spring.datasource.validationQuery=SELECT 1 FROM DUAL spring.datasource.testWhileIdle=true spring.datasource.testOnBorrow=false spring.datasource.testOnReturn=false spring.datasource.poolPreparedStatements=true spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 spring.datasource.filters=stat,wall,log4j spring.datasource.connectionProperties=druid.stat.mergdruid.stat.slowSqlMillis=5000
2.5.2 redis的配置详细说明
Redis是一个缓存, 消息中间件及具有丰富特性的键值存储系统。 Spring Boot为Jedis客户端库和由Spring Data Redis提供的
基于Jedis客户端的抽象提供自动配置。 spring-boot-starter-redis ‘Starter POM’为收集依赖提供一种便利的方式。
连接Redis :引入Spring boot 对redies 的支持
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency>
Redies配置
#redis spring.redis.host=localhost spring.redis.port=6379 spring.redis.password=xxx spring.redis.pool.maxActive=8 spring.redis.pool.maxWait=-1 spring.redis.pool.maxIdle=8 spring.redis.pool.minIdle=0 spring.redis.timeout=0
2.6 自动装配Spring Bean
pring Boot会检查你发布的jar中是否存在META-INF/spring.factories文件。我们在使用Spring Boot时使用最多的就是starter,我们在使用某个功能时,开发者不需要关注各种依赖库的处理,不需要具体的配置信息,直接@Autowired就可以注入这些Bean。
因此我们可以自定义一些starter,当需要启动一些Bean时只需要在src/main/resources目录下新建META-INF文件夹,然后新建spring.factories文件,这个文件用于告诉Spring Boot去找指定的自动配置文件,这些文件将会被装载成Spring Bean:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.jb.cache.configure.CacheConfigure,\com.jb.cache.configure.EntityCacheConfig
2.7 静态文件
Spring Boot能大大简化WEB应用开发的原因, 最重要的就是遵循“约定优于配置”这一基本原则。Spring Boot的关于静态资源的默认配置已经完全满足绝大部分WEB应用的需求。没必要去弄手续繁杂的自定义,用Spring Boot的约定就好了。
在Maven 工程目录下,所有静态资源都放在src/main/resource目录下,结构如下:
页面可以这样访问
<img src="images/newDemo.jpg">
添加自定义:
注意是添加,不是替换,添加不影响原来的默认约定。非要自定义,那就配置类继承WebMvcConfigurerAdapter
@Configurationpublic class MyWebAppConfig extends WebMvcConfigurerAdapter {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry){ registry.addResourceHandler("/myResource/**").addResourceLocations("classpath:/myRes ource/");super.addResourceHandlers(registry);}
这个是添加了一个新位置
3 swagger配置及使用
Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API。具体效果如下图所示:
在 pom.xml 中加入Swagger2的依赖
创建swagger2配置类:
如下代码所示,通过 @Configuration 注解,让Spring来加载该类配置。再通过 @EnableSwagger2 注解来启用Swagger2
@Configuration@EnableSwagger2public class SwaggerConfigure { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.xxx.xx")) .paths(PathSelectors.any())//TODO 修改为正则匹配 .build(); } /** * api基本信息内容 * @Title: apiInfo * @Description: TODO * @param * @return ApiInfo * @throws */ private ApiInfo apiInfo() { //TODO 从配置文件读取 return new ApiInfoBuilder() .title("xxxxxAPI") .description("xxxxxxxx") .termsOfServiceUrl("xxxxxx") .contact("平台组") .version("3.0.0") .build(); }}
通过 createRestApi 函数创建 Docket 的Bean之后, apiInfo() 用来创建该Api的基本信息(这些基本信息会展现在文档页面中)。 select() 函数返回一个 ApiSelectorBuilder 实例用来控制哪些接口暴露给Swagger来展现,本例采用指定扫描的包路径来定义,Swagger会扫描该包下所有Controller定义的API,并产生文档内容(除了被 @ApiIgnore 指定的请求)。
添加文档内容
在完成了上述配置后,其实已经可以生产文档内容,但是这样的文档主要针对请求本身,而描述主要来源于函数等命名产生,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。如下所示,我们通过 @ApiOperation 注解来给API增加说明、通过 @ApiImplicitParams 、 @ApiImplicitParam 注解来给参数增加说明。
@ApiOperation(value ="获取模型类型对应的属性",notes = "模型")@ApiImplicitParam(name="clsID",value="类型id", paramType="query",required=true,dataType="String")@RequestMapping(value = "getNonGroupAttrsOfClass.do", method = RequestMethod.POST)@ResponseBodypublic List<TbModelClsattr>getNonGroupAttrsOfClass(String clsID) { List<TbModelClsattr> list = bfObjectModelService .getNonGroupAttrsOfClass(clsID); return list; }
启动Spring Boot访问:http://localhost:8080/swagger-ui.html,可以看到就能看到前文所展示的RESTful API的页面
API文档访问与调试
在上图请求的页面中,我们看到user的Value是个输入框?是的,Swagger除了查看接口功能外,还提供了调试测试功能,我们可以点击上图中右侧的Model Schema(黄色区域:它指明了User的数据结构),此时Value中就有了user对象的模板,我们只需要稍适修改,点击下方 “Try it out!” 按钮,即可完成了一次请求调用!(具体使用请自行百度这里只提供一个配置说明)
4 Spring Boot单元测试
单元测试 是针对 程序的最小单元 来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。一个单元可能是单个程序、类、对象、方法等—–维基百科
Junit基本注解介绍
@BeforeClass
在所有测试方法前执行一次,一般在其中写上整体初始化的代码
@AfterClass
在所有测试方法后执行一次,一般在其中写上销毁和释放资源的代码
@Before
在每个测试方法前执行,一般用来初始化方法(比如我们在测试别的方法时,类中与其他测试方法共享的值已经被改变,为了保证测试结果的有效性,我们会在@Before注解的方法中重置数据)
@After
在每个测试方法后执行,在方法执行完成后要做的事情
@Test(timeout = 1000)
测试方法执行超过1000毫秒后算超时,测试将失败
@Test(expected = Exception.class)
测试方法期望得到的异常类,如果方法执行没有抛出指定的异常,则测试失败
@Ignore(“not ready yet”)
@Test
执行测试时将忽略掉此方法,如果用于修饰类,则忽略整个类
@RunWith
在JUnit中有很多个Runner,他们负责调用你的测试代码,每一个Runner都有各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码。
如果我们只是简单的做普通Java测试,不涉及Spring Web项目,你可以省略@RunWith注解,这样系统会自动使用默认Runner来运行你的代码。
5 MockMvc测试
5.1 MockMvcBuilder
MockMvcBuilder是用来构造MockMvc的构造器,其主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(此种方式并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。对于我们来说直接使用静态工厂MockMvcBuilders创建即可。
@RunWith(SpringRunner.class)@SpringBootTest(classes={ModelApplication.class})@AutoConfigureMockMvc@Transactional //提供事物回滚机制public class IncotermsRestServiceTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { //构造MockMvc this.mockMvc= MockMvcBuilders.webAppContextSetup(this.wac).build(); } ...}
注意:
(1)@SpringBootTest:Spring Boot测试环境使用,classes指定程序启动类
(2)通过@Autowired WebApplicationContext wac:注入web环境的ApplicationContext容器;
(3)然后通过MockMvcBuilders.webAppContextSetup(wac).build()创建一个MockMvc进行测试;
(4)@Transactional :添加可以是事物回滚,不会因为测试数据而造成数据的错误。
看一个具体的例子:
@Testpublic void cmdGetAppAttrOfAppCls() throws Exception{ String result= this.mockMvc.perform(post("/appAttr/cmdGetAppAttrOfAppCls.do",).param("appID","123").param("clsID","345")) .andDo(print()).andReturn().getResponse().getContentAsString(); System.out.println(result.toString()); Assert.assertNotNull(result);}
perform:执行一个RequestBuilder请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理;
param:添加control需要的参数
andDo:添加ResultHandler结果处理器,比如调试时打印结果到控制台;
andReturn:最后返回相应的MvcResult;然后进行自定义验证进行下一步的异步处理;
最后使用断言来进行返回值判断。
- F1V3.0-8 Springboot基本使用及要点
- F1V3.0-图形-如何下载及使用离线的瓦片地图
- F1V3.0-1 单体应用的硬伤及解决之道
- F1V3.0-24 UI前端模块的发布及部署
- F1V3.0-2 平台2.X优点继承及问题解决
- F1V3.0-19 UI新控件及新功能简介
- log4j 基本使用要点
- springboot基本使用笔记----添加jsp支持及打包部署
- springboot基本使用
- SpringBoot: jpa基本使用
- Springboot使用RedisTemplate基本步骤
- F1V3.0-图形-GIS基础知识
- F1V3.0-图形-本地自成图jar类库安装到本地仓库及私服
- OC基本语法及知识要点汇总
- springboot基本使用笔记----添加socket服务及获取spring bean
- 【STL】vector要点及使用
- 【STL】deque要点及使用
- 【STL】stack要点及使用
- java中的==和equals()以及instanceof
- Android 如何使用GPU硬件加速
- O
- ViewPager无限轮播图
- google amp 技术学习
- F1V3.0-8 Springboot基本使用及要点
- 面向对象—(JDBC(2))
- [php]mac终于完成了php配置
- 神经网络(2)
- Oracle提示ora-01031:insufficient privileges解决方案
- HTML5 基本语法
- SAP HANA SQL REPLACE替换字符串
- 如何从apache官方下载以及window下的安装
- 监听器,过滤器,拦截器区别