Spring入门——基础详解
来源:互联网 发布:淘宝店铺运动服简介 编辑:程序博客网 时间:2024/05/17 21:58
什么是Spring?
Spring简介
Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架(提供与第三方持久层框架的良好整合,并简化了底层的数据库访问)。
Spring特征
- 轻量:Spring是非侵入式的,典型地,Spring应用中的对象不依赖于Spring的特定类。
- IoC(控制反转):方便解耦,简化开发,将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。
- AOP(面向切面编程):通过分离应用的业务逻辑与系统级服务进行内聚性的开发。支持日志和事务。
- 容器:Spring是一种容器,包含并管理应用对象的配置和生命周期。
- 框架:Spring可以将简单的组件配置、组合成为复杂的应用。应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等)。
- MVC:是一个全功能的构建 Web应用程序的 MVC 实现。
Spring概述
Spring带来了复杂Java EE开发的春天。
搭建Spring环境步骤
安装Spring Tool Suite
Spring Tool Suite是定制开发Spring应用程序的基于Eclipse的开发环境,提供了一个现成的使用环境中实施,调试,运行和部署Spring应用程序。
安装请参考我的上一篇文章Eclipse安装以及集成Java开发环境插件的安装。
下载相关jar包
Spring官网:https://spring.io/。
Spring官网下载对应的版本:http://repo.spring.io/release/org/springframework/spring/。
Spring必须依赖记录日志包:
http://commons.apache.org/proper/commons-logging/download_logging.cgi
我是用的是这个版本spring-framework-4.3.10这个版本
解压我们下载好的spring-framework-4.3.10.RELEASE-dist文件,打开\libs文件夹,这里就是Spring提供的完整jar包,如下:
记录日志包,解压如下图:
Spring IoC
控制反转(Inversion of Control),也被称为依赖注入(Dependency Injection),用来减低程序代码之间耦合。
创建Project并导入相关jar包
属性注入
Spring通过 setter 访问器实现了对属性的赋值。
编写HelloWorld实体类
package com.demo.bean;public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public void hello() { System.out.println("Hello:"+name); }}
创建applicationContext.xml文件
右键Src—>New—>Spring,如下图:
编写applicationContext.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- id:唯一标识 class:bean的全类名,反射方式在IoC容器创建bean,bean中必须有无参构造其 --> <bean id="helloWorld" class="com.demo.bean.HelloWorld"> <!-- name—>setName value—>name --> <property name="name" value="Spring"></property> </bean></beans>
编写测试类TestHelloWorld
package com.demo.test;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.demo.bean.HelloWorld;public class TestHelloWorld { @Test public void test() {// HelloWorld helloWorld=new HelloWorld();// helloWorld.setName("Spring"); //1.创建Spring IoC容器对象 ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从IoC容器获取bean实例 HelloWorld helloWorld=(HelloWorld) ac.getBean("helloWorld");//对应配置bean中的id helloWorld.hello(); }}
测试运行
构造注入
Spring提供通过构造赋值。
编写Car类
package com.demo.bean;public class Car { private String brand; private String corp; private double price; private int maxSpeed; @Override public String toString() { return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price + ", maxSpeed=" + maxSpeed + "]"; } public Car(String brand, String corp, int maxSpeed) { super(); this.brand = brand; this.corp = corp; this.maxSpeed = maxSpeed; } public Car(String brand, String corp, double price) { super(); this.brand = brand; this.corp = corp; this.price = price; }}
修改applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?><!-- 声明p命名空间 --><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- id:唯一标识 class:bean的全类名,反射方式在IoC容器创建bean,bean中必须有无参构造其 使用p命名空间注入属性值 --> <bean id="helloWorld" class="com.demo.bean.HelloWorld" p:name="Spring"/> <!-- 构造注入 <constructor-arg/> 表示构造方法的参数,不区分顺序 使用index指定参数的位置索引,从0开始 使用type指定参数的类型 使用<![CDATA[]]>标记或把特殊字符替换为实体引用 --> <bean id="carAudi" class="com.demo.bean.Car"> <constructor-arg value="Audi" index="0"></constructor-arg> <constructor-arg index="1"> <value><![CDATA[<ShangHai>]]></value> </constructor-arg> <constructor-arg value="360000" type="double"></constructor-arg> </bean> <!-- 5个预定义实体引用: < < > > ' ' " " & & --> <bean id="carBaoma" class="com.demo.bean.Car"> <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg> <constructor-arg type="java.lang.String"> <value><ShangHai></value> </constructor-arg> <constructor-arg value="240" type="int"></constructor-arg> </bean></beans>
编写测试类
package com.demo.test;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.demo.bean.Car;import com.demo.bean.HelloWorld;public class TestHelloWorld { @Test public void test() { //1.创建Spring IoC容器对象 ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从IoC容器获取bean实例 HelloWorld helloWorld=(HelloWorld) ac.getBean("helloWorld"); helloWorld.hello(); Car carAudi=(Car) ac.getBean("carAudi"); System.out.println(carAudi.toString()); Car carBaoma=(Car) ac.getBean("carBaoma"); System.out.println(carBaoma.toString()); }}
运行测试
引用其他Bean组件
Spring定义Bean可以相互引用,从而建立依赖关系,使用 ref 属性或< ref/>子元素实现。
编写Person类
package com.demo.bean;public class Person { private String name; private int age; private Car car; @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; }}
修改applicationContext.xml文件
"><!-- 声明p命名空间 --><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- id:唯一标识 class:bean的全类名,反射方式在IoC容器创建bean,bean中必须有无参构造其 使用p命名空间注入属性值 --> <bean id="helloWorld" class="com.demo.bean.HelloWorld" p:name="Spring"/> <!-- 构造注入 <constructor-arg/> 表示构造方法的参数,不区分顺序 使用index指定参数的位置索引,从0开始 使用type指定参数的类型 使用<![CDATA[]]>标记或把特殊字符替换为实体引用 --> <bean id="carAudi" class="com.demo.bean.Car"> <constructor-arg value="Audi" index="0"></constructor-arg> <constructor-arg index="1"> <value><![CDATA[<ShangHai>]]></value> </constructor-arg> <constructor-arg value="360000" type="double"></constructor-arg> </bean> <!-- 5个预定义实体引用: < < > > ' ' " " & & --> <bean id="carBaoma" class="com.demo.bean.Car"> <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg> <constructor-arg type="java.lang.String"> <value><ShangHai></value> </constructor-arg> <constructor-arg value="240" type="int"></constructor-arg> </bean><!-- ref属性 或 <ref>标签引用bean 级联属性赋值 注意:属性需先初始化后才可为级联属性赋值,否则出异常,与Struts2不同 --><bean id="person" class="com.demo.bean.Person" p:name="Hjw" p:age="19" p:car-ref="carBaoma" p:car.price="1000000"> <!-- <property name="car"> <ref bean="carBaoma"/> </property> --> <!-- 内部bean的使用 <property name="car"> <bean class="com.demo.bean.Car"> <constructor-arg value="Benchi"></constructor-arg> <constructor-arg value="JinKou"></constructor-arg> <constructor-arg value="1000000" type="double"></constructor-arg> </bean> </property> --> <!-- 测试赋值null <null/> <property name="car"><null/></property> --> </bean></beans>
编写测试类
package com.demo.test;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.demo.bean.Car;import com.demo.bean.HelloWorld;import com.demo.bean.Person;public class TestHelloWorld { @Test public void test() { //1.创建Spring IoC容器对象 ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从IoC容器获取bean实例 Person person=(Person) ac.getBean("person"); System.out.println(person.toString()); }}
测试如下
注入集合类型的属性
注入集合类型分为:
- < List>标签注入 使用 < value>,< ref>等标签注入集合元素
- < set>标签注入 使用 < value>,< ref>等标签注入集合元素
- < map>标签注入 使用< enrty>包含 < key>和< value>
- < props>标签注入 键和值通常是字符串类型
分别编写PersonList,PersonSet,PersonMap,DataSource实体类
修改applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?><!-- 声明p命名空间 --><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <!-- id:唯一标识 class:bean的全类名,反射方式在IoC容器创建bean,bean中必须有无参构造其 使用p命名空间注入属性值 --> <bean id="helloWorld" class="com.demo.bean.HelloWorld" p:name="Spring" /> <!-- 构造注入 <constructor-arg/> 表示构造方法的参数,不区分顺序 使用index指定参数的位置索引,从0开始 使用type指定参数的类型 使用<![CDATA[]]>标记或把特殊字符替换为实体引用 --> <bean id="carAudi" class="com.demo.bean.Car"> <constructor-arg value="Audi" index="0"></constructor-arg> <constructor-arg index="1"> <value><![CDATA[<ShangHai>]]></value> </constructor-arg> <constructor-arg value="360000" type="double"></constructor-arg> </bean> <!-- 5个预定义实体引用: < < > > ' ' " " & & --> <bean id="carBaoma" class="com.demo.bean.Car"> <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg> <constructor-arg type="java.lang.String"> <value><ShangHai></value> </constructor-arg> <constructor-arg value="240" type="int"></constructor-arg> </bean> <!-- ref属性 或 <ref>标签引用bean 级联属性赋值 注意:属性需先初始化后才可为级联属性赋值,否则出异常,与Struts2不同 --> <bean id="person" class="com.demo.bean.Person" p:name="Hjw" p:age="19" p:car-ref="carBaoma" p:car.price="1000000"> <!-- <property name="car"> <ref bean="carBaoma"/> </property> --> <!-- 内部bean的使用 <property name="car"> <bean class="com.demo.bean.Car"> <constructor-arg value="Benchi"></constructor-arg> <constructor-arg value="JinKou"></constructor-arg> <constructor-arg value="1000000" type="double"></constructor-arg> </bean> </property> --> <!-- 测试赋值null <null/> <property name="car"><null/></property> --> </bean> <!-- List类型的属性赋值 --> <bean id="personList" class="com.demo.bean.PersonList" p:name="Hxn" p:age="19" p:carList-ref="carsUtilList"> </bean> <!-- Set类型的属性赋值 --> <bean id="personSet" class="com.demo.bean.PersonSet" p:name="Hxn" p:age="19" p:carSet-ref="carsUtilSet"> </bean> <!-- Map类型的属性赋值 map节点中的enrty --> <bean id="personMap" class="com.demo.bean.PersonMap" p:name="Hxn" p:age="19" p:carMap-ref="carsUtilMap"> </bean> <!-- properties配置模拟链接数据库 props中的子节点--> <bean id="dataSource" class="com.demo.bean.DataSource" p:properties-ref="propsUtil"> </bean> <!-- 声明util命名空间 配置单例集合bean,供多个bean引用 --> <util:list id="carsUtilList"> <ref bean="carAudi"/> <ref bean="carBaoma"/> </util:list> <util:set id="carsUtilSet"> <ref bean="carAudi"/> <ref bean="carBaoma"/> </util:set> <util:map id="carsUtilMap"> <entry key="1" value-ref="carAudi"></entry> <entry key="2" value-ref="carBaoma"></entry> </util:map> <util:properties id="propsUtil"> <prop key="username">root</prop> <prop key="password">root</prop> <prop key="url">jdbc:mysql:///test</prop> <prop key="driver_class">com.mysql.jdbc.Driver</prop> </util:properties></beans>
测试如下
Spring AOP
面向切面编程(Aspect Oriented Programming)是软件编程思想发展到一定的阶段产物,是面向对象编程的有益补充,AOP适用于具有横切逻辑场合(访问控制,事务管理,性能检测等)。
使用AspectJ注解定义切面
使用AspectJ注解实现日志输出功能。
创建Project并导入相关jar包
创建IArithmeticCalculator接口(加减乘除)
package com.demo.aop;/** * 加减乘除 * @author JackHu * */public interface IArithmeticCalculator { int add(int i,int j); int sub(int i,int j); int mul(int i,int j); int div(int i,int j);}
创建ArithmeticCalculatorImpl实现类
package com.demo.aop.impl;import org.springframework.stereotype.Component;import com.demo.aop.IArithmeticCalculator;@Component("arithmeticCalculator") //public class ArithmeticCalculatorImpl implements IArithmeticCalculator { @Override public int add(int i, int j) { int result=i+j; return result; } @Override public int sub(int i, int j) { int result=i-j; return result; } @Override public int mul(int i, int j) { int result=i*j; return result; } @Override public int div(int i, int j) { int result=i/j; return result; }}
创建applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 自动扫描的包 --> <context:component-scan base-package="com.demo.aop.*"></context:component-scan> <!-- 使AspectJ 注解:自动为匹配的类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>
编写测试类AirthmeticCalculatorTest
package test;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.demo.aop.IArithmeticCalculator;public class AirthmeticCalculatorTest { @Test public void test() { ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); IArithmeticCalculator aci=ac.getBean(IArithmeticCalculator.class); System.out.println(aci.getClass().getName()); int add=aci.add(5, 5); System.out.println(add); int dic=aci.div(5, 0); System.out.println(dic); }}
编写LoggingAspect日志类
package com.demo.aop.aspect;import java.util.Arrays;import java.util.List;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;@Aspect //声明切面@Component //放到IoC容器public class LoggingAspect { /** * 前置通知 * * @param jPoint */ @Before("execution(* com.demo.aop.IArithmeticCalculator.*(..))") public void beforeMethod(JoinPoint jPoint) { String methodName = jPoint.getSignature().getName(); //方法名 List<Object> args = Arrays.asList(jPoint.getArgs()); //参数 System.out.println("This method " + methodName + " begins " + args); } /** * 后置通知,无论该方法是否出现异常 * * @param jPoint */ @After("execution(* com.demo.aop.IArithmeticCalculator.*(..))") public void afterMethod(JoinPoint jPoint) { String methodName = jPoint.getSignature().getName(); System.out.println("This method " + methodName + " ends "); } /** * 返回通知 * * @param jsPoint * @param returnValue */ @AfterReturning(pointcut = "execution(* com.demo.aop.IArithmeticCalculator.*(..))", returning = "returnValue") public void afterReturning(JoinPoint jsPoint, Object returnValue) { System.out.println("return:" + returnValue); } /** * 异常通知 * * @param jPoint * @param e */ @AfterThrowing(pointcut = "execution(* com.demo.aop.IArithmeticCalculator.*(..))", throwing = "e") public void afterThrowing(JoinPoint jPoint, RuntimeException e) { System.out.println(jPoint.getSignature().getName() + "方法发生异常:" + e); }}
测试运行
实现环绕通知
修改LoggingAspect类:
package com.demo.aop.aspect;import java.util.Arrays;import java.util.List;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.springframework.stereotype.Component;@Aspect@Componentpublic class LoggingAspect { /** * 环绕通知 类似于动态代理的全过程:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法 必须有返回值(目标方法的返回值) * * @param pJoinPoint */ @Around("execution(* com.demo.aop.IArithmeticCalculator.*(..))") public Object around(ProceedingJoinPoint pJoinPoint) { Object result = null; String methodName = pJoinPoint.getSignature().getName(); List<Object> args = Arrays.asList(pJoinPoint.getArgs()); try { // 前置通知 System.out.println("This method " + methodName + " begins " + args); // 执行目标方法 result = pJoinPoint.proceed(); // 返回通知 System.out.println("This method" + methodName + " ends with " + result); } catch (Throwable e) { // 异常通知 System.out.println("This method" + methodName + "exception:" + e); } // 后置通知 System.out.println("This method" + methodName + "ends"); return result; }}
测试如图:
重用切面表达式&&切面优先级
package com.demo.aop.aspect;import java.util.Arrays;import java.util.List;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Order(2) //声明切面的优先级,数字越小优先级越大@Aspect@Componentpublic class LoggingAspect { /** * 声明切面表达式 */ @Pointcut("execution(* com.demo.aop.IArithmeticCalculator.*(..))") public void declareJoinPointExpression() {} /** * 前置通知 * * @param jPoint */ @Before("declareJoinPointExpression()") //替换 public void beforeMethod(JoinPoint jPoint) { String methodName = jPoint.getSignature().getName(); List<Object> args = Arrays.asList(jPoint.getArgs()); System.out.println("This method " + methodName + " begins " + args); } /** * 后置通知,无论该方法是否出现异常 * * @param jPoint */ @After("declareJoinPointExpression()") public void afterMethod(JoinPoint jPoint) { String methodName = jPoint.getSignature().getName(); System.out.println("This method " + methodName + " ends "); } /** * 返回通知 * * @param jsPoint * @param returnValue */ @AfterReturning(pointcut = "declareJoinPointExpression()", returning = "returnValue") public void afterReturning(JoinPoint jsPoint, Object returnValue) { System.out.println("return:" + returnValue); } /** * 异常通知 * * @param jPoint * @param e */ @AfterThrowing(pointcut = "declareJoinPointExpression()", throwing = "e") public void afterThrowing(JoinPoint jPoint, RuntimeException e) { System.out.println(jPoint.getSignature().getName() + "方法发生异常:" + e); } /** * 环绕通知 类似于动态代理的全过程:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法 必须有返回值(目标方法的返回值) * * @param pJoinPoint */// @Around("declareJoinPointExpression()")// public Object around(ProceedingJoinPoint pJoinPoint) {// Object result = null;// String methodName = pJoinPoint.getSignature().getName();// List<Object> args = Arrays.asList(pJoinPoint.getArgs());//// try {// // 前置通知// System.out.println("This method " + methodName + " begins " + args);// // 执行目标方法// result = pJoinPoint.proceed();// // 返回通知// System.out.println("This method"+methodName+" ends with "+result);// // } catch (Throwable e) {// // 异常通知// System.out.println("This method" + methodName + "exception:" + e);// }// // 后置通知// System.out.println("This method" + methodName + "ends");// return result;// }}
使用Schema配置定义切面
删注解
修改applicationContext.xml如下:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 配置bean --> <bean id="aci" class="com.demo.aop.impl.ArithmeticCalculatorImpl"></bean> <!-- 配置Aspect Bean--> <bean id="loggingAspect" class="com.demo.aop.aspect.LoggingAspect"></bean> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(* com.demo.aop.IArithmeticCalculator.*(..))" id="pointcut"/> <!-- 配置切面及通知 --> <aop:aspect ref="loggingAspect" order="2"> <aop:before method="beforeMethod" pointcut-ref="pointcut"/> <aop:after method="afterMethod" pointcut-ref="pointcut"/> <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="returnValue"/> <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/> <!-- <aop:around method="around" pointcut-ref="pointcut"/> --> </aop:aspect> </aop:config></beans>
总结
这样我们一个简单的Spring示例就已经完成了,欢迎同学们学习哈!!!
- Spring入门——基础详解
- Spring入门详解【基础扫盲】
- spring security 基础入门(配置详解)
- Spring注解详解(基础入门)
- Spring学习详解(1)——Spring入门详解
- Spring学习笔记——基础入门
- Struts2入门——基础详解
- Hibernate入门——基础详解
- MySQL基础入门—SELECT语句详解
- SSM框架(Spring Spring MVC Mybatis)基础入门学习2——Spring入门实例
- 零基础入门学习——Spring Boot注解
- Spring基础-入门讲解
- spring入门基础
- spring cloud入门基础
- spring-boot 基础入门
- Spring MVC基础入门
- [Spring MVC] 入门基础
- Spring MVC入门基础
- eayUI datagrid 列合并、合并列
- LeetCode Convert BST to Greater Tree
- 541. Reverse String II
- MyBatis 示例之存储过程(三)
- EventBus源码解析03-事件的发送
- Spring入门——基础详解
- java服务端,微信支付功能的实现
- 一个简单的动态内表alv案例
- 成都旅游小吃攻略
- DOCTYPE
- 凭什么杀程序员祭天?
- 数据存储 SharedPreference~properties
- 编写一个java程序,从1加到100,每做一次加法,就休眠1秒,当程序运行过程中,杀死这个程序。 再次运行,还能从上次的计算结果继续下去
- GNU/Linux-MariaDB