这一篇主要讲Spring一些基础的内容。

概述

Spring 是一个非常火的框架,尤其是在Web开发领域,和Struts以及Hibernate构成了SSH三剑客。当时Web开发的另一个组合是LAMP,即 Linux+Apache+MySQL+PHP。我在前端方面基本没有实战经验,对js等技术也还是停留在概念和语法方面,所以扬长避短,我对 Spring以及Hibernate特别感兴趣。

当年Spring是作为EJB的“替代者”横空出世的,其创始人Rod Johnson还写了一本《J2EE development without EJB》来推行这个框架,这也是一本关于Spring很经典的书,不过最好是在接触Spring一段时间后再去阅读,效果会好一点。

Spring最主要的特点有两个:IoC和AOP,这也是J2EE开发企业软件时经常碰到的问题:1)对象太多如何管理;2)共同逻辑和业务逻辑纠缠在一起,错综复杂,如何解耦。

这篇文章主要关注3个方面:IoC、AOP和数据库访问。这里我们假设所有需要的jar都已经准备就绪。

IoC

IoC的全称是Inversion of Control,中文称为控制反转, Martin Flower由根据它创造了一个新词:Dependency Injection,中文称为依赖注入。这两个词讲的是一回事儿。

IoC的实质是如何管理对象,传统意义上我们使用new方式来创建对象,但在企业应用开发的过程中,大量的对象创建都在程序中维护很容易造成资源浪费,并且不利于程序的扩展。

实现IoC通常有三种方式:

1)利用接口或者继承,一般以接口较多。这种实现方式和我们平时提到的lazy load有异曲同工之妙。

2)构造函数注入。

3)属性注入。

IoC是Spring框架的核心,接下来我们来探索一下Spring中IoC的风采。

IoC简单示例

我们先来定义一个简单的接口和实现:

1 public interfaceUserDao {2 voidsave();3 }4

5 public class UserDaoImpl implementsUserDao6 {7

8 public voidsave() {9 System.out.println("save() is called.");10 }11

12 }

然后是在classpath下创建一个beans.xml文件(这个文件名不是必须这样的):

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

接下来是测试代码:

1 private static voidtest1()2 {3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/beans.xml");4 UserDao userDao = (UserDao)ctx.getBean("userDaoImpl");5 userDao.save();6 }

输出结果如下:

save() is called.

我们还可以通过工厂方式来创建对象。

通过静态工厂创建Bean

添加一个类,如下:

1 public classUserDaoFactory {2

3 public staticUserDao getUserDao()4 {5 return newUserDaoImpl();6 }7 }

在beans.xml中,添加如下内容:

1

测试代码和执行结果和上面类似,不再赘述。

通过实例工厂创建Bean

添加如下类:

1 public classUserDaoFactory22 {3 publicUserDao getUserDao()4 {5 return newUserDaoImpl();6 }7 }

这个类和UserDaoFactory唯一的区别是这里的getUserDao是实例方法,而不是静态方法。

在beans.xml中追加如下内容:

1

2

测试方法和结果同上。

对象的生命周期

我们可以通过设置bean节点的scope属性来控制对象的声明周期,它包含两个可选值:

1)singleton,表明系统中对于同一个对象,只保留一个实例。

2)prototype,表明系统中每次获取bean时,都新建一个对象。

我们修改beans.xml文件:

1

2

这两个bean指向同一个类型,但是scope的设置不同。

下面是测试方法:

1 private static voidscopeTest()2 {3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/scope.xml");4 System.out.println("=====Singleton test=====");5 UserDao userDao1A = (UserDao)ctx.getBean("userDaoImpl");6 UserDao userDao1B = (UserDao)ctx.getBean("userDaoImpl");7 System.out.println("userDao1A == userDao1B:" + (userDao1A==userDao1B));8 System.out.println("=====Prototype test=====");9 UserDao userDao2A = (UserDao)ctx.getBean("userDaoImpl2");10 UserDao userDao2B = (UserDao)ctx.getBean("userDaoImpl2");11 System.out.println("userDao2A == userDao2B:" + (userDao2A==userDao2B));12 }

执行结果如下:

=====Singleton test=====userDao1A== userDao1B:true

=====Prototype test=====userDao2A== userDao2B:false

如何设置对象属性

上面的示例中,我们的对象中没有包含属性,对于业务对象来说,这一般是不现实。实际中的对象或多或少都会有一些属性。

Spring支持两种方式对属性赋值:set方式和构造函数。

下面我们会分别描述两种方式,但首先我们需要展示业务对象:

定义UserServiceBean

这是一个典型的学生信息,包括学号、姓名、爱好和成绩。

通过Set方式为对象属性赋值

我们在beans.xml中追加如内容:

1

2

3

4

5

6

7 羽毛球

8 看电影

9 弹吉他

10

11

12

13

14

15

16

17

18

19

上面是典型的为属性赋值的示例,其中属性不仅包括简单属性(整数、字符串),也包含了复杂属性(List、Map),还有其他的bean。

下面是测试代码:

1 private static voidpropertyTest1()2 {3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/beans.xml");4 UserServiceBean userService = (UserServiceBean)ctx.getBean("userService");5 printUserService(userService);6 }7

8 private static voidprintUserService(UserServiceBean userService)9 {10 System.out.println("编号:" +userService.getUserID());11 System.out.println("姓名:" +userService.getUserName());12 System.out.println("爱好:");13 for(String hobby:userService.getHobbies())14 {15 System.out.println(hobby);16 }17 System.out.println("学习成绩:");18 for(Entryentry:userService.getScores().entrySet())19 {20 System.out.println(entry.getKey() + "\t" +entry.getValue());21 }22 userService.getUserDao().save();23 }

输出结果如下:

编号:1姓名:张三

爱好:

羽毛球

看电影

弹吉他

学习成绩:

数据结构90编译原理85离散数学82save() is called.

通过构造函数为对象属性赋值

我们也可以通过构造函数来为对象赋值,在上面定义UserServiceBean时,我们已经添加了一个构造函数。下面来看beans.xml中的配置:

1

2

3

4

5

6

7 羽毛球

8 看电影

9 弹吉他

10

11

12

13

14

15

16

17

18

19

测试代码和输出结果同上。

需要注意:我们定义的业务对象应该保留默认的构造函数。

使用Annotation来定位Bean

在Spring中,除了在xml配置文件中定义对象,我们还可以使用Annotation来定位,这位我们提供了很大的方便。

这里我们使用的Annotation主要包括:@Resource/@Autowried/@Qualifier。

来看下面的示例:

1 public classUserServiceBean22 {3 privateString userID;4 privateString userName;5 @Resource(name="userDaoImpl")6 privateUserDao userDao1;7 privateUserDao userDao2;8

9 @Autowired(required=false)10 @Qualifier("userDaoImpl")11 privateUserDao userDao3;12

13 @Autowired(required=false)14 @Qualifier("userDaoImpl3")15 privateUserDao userDao4;16

17 public voidsetUserID(String userID) {18 this.userID =userID;19 }20 publicString getUserID() {21 returnuserID;22 }23 public voidsetUserName(String userName) {24 this.userName =userName;25 }26 publicString getUserName() {27 returnuserName;28 }29 @Resource30 public voidsetUserDao2(UserDao userDao2) {31 this.userDao2 =userDao2;32 }33 publicUserDao getUserDao2() {34 returnuserDao2;35 }36

37 public voidtest()38 {39 userDao1.save();40 userDao2.save();41 System.out.println(userDao3.getClass().getName());42 userDao3.save();43 }44 }

测试方法:

1 private static voidannotationTest()2 {3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/annotation.xml");4 UserServiceBean2 userService = (UserServiceBean2)ctx.getBean("userService");5

6 userService.test();7 }

输出结果如下:

save() is called.

save() is called.

sample.spring.ioc.UserDaoImpl

save() is called.

我们来对上面示例中出现的Annotation来进行说明。

1 @Resource(name="userDaoImpl")2 private UserDao userDao1;

这是定义在字段上的Annotation,是指userDao1使用xml配置文件中定义的名为“userDaoImpl”的bean进行填充。

1 @Autowired(required=false)2 @Qualifier("userDaoImpl")3 private UserDao userDao3;

这是第二种类型的Annotation,它把Autowired和Qualifier组合在一起使用,Qualifier来设置bean的名 称,Autowired来设置bean找不到时的行为,required为true时会抛出异常,required为false时会返回null。

1 @Resource2 public voidsetUserDao2(UserDao userDao2) {3 this.userDao2 =userDao2;4 }

这是作用在setter上的Annotation,@Resource 可以不写明name参数,这时Spring会首先按照名字然后按照数据类型的方式去定位bean。

自动加载对象定义

对于大型系统来说,我们可能会创建大量的类,如果这些类的声明都需要写在xml文件里的话,会产生额外大量的工作。

Spring提供了一种简单的机制让我们的对象可以自动注册。

我们可以在beans.xml中添加如下内容:

1

然后我们可以在sample.spring.ioc包下的对象,添加@Component/@Service/@Controller/@repository,这样Spring会自动将带有这些Annotation的类进行注册。

下面是一个示例:

自动注册Bean示例

这个类和上面定义的UserServiceBean2非常相似,需要注意在类前面添加的Annotation信息。

我们不需要在xml文件中手动定义这个bean,Spring会进行自动注册,注册的bean名称是userService。

AOP

我们在Java回顾之反射中已经设计了一个简单的AOP框架,通常情况下,对于AOP,我们有两种方式来实现。

使用DynamicProxy实现AOP

下面是一个简单的示例,首先定义业务对象:

1 public interfaceUserDao {2

3 voidsave();4 }5

6 public class UserDaoImpl implementsUserDao7 {8 privateString name;9

10 public voidsave() {11 System.out.println("save() is called for " +name);12 }13

14 public voidsetName(String name) {15 this.name =name;16 }17

18 publicString getName() {19 returnname;20 }21 }

下面是一个实现了InvocationHandler的类:

1 public class ProxyFactory implementsInvocationHandler2 {3 privateObject target;4

5 publicObject createUserDao(Object target)6 {7 this.target =target;8 return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),9 this.target.getClass().getInterfaces(), this);10 }11

12 publicObject invoke(Object proxy, Method method, Object[] args)13 throwsThrowable {14

15 UserDaoImpl userDao =(UserDaoImpl)target;16 Object result = null;17 if(userDao.getName() != null)18 {19 result =method.invoke(target, args);20 }21 else

22 {23 System.out.println("The name is null.");24 }25 returnresult;26 }27 }

接下来是测试代码:

1 private static voidtest1()2 {3 ProxyFactory pf = newProxyFactory();4 UserDao userDao = (UserDao)pf.createUserDao(newUserDaoImpl());5 userDao.save();6 }

执行结果如下:

The name is null.

这是因为userDao的类型是UserDao,它是一个接口,并没有定义name字段,因此name=null。

使用Cglib实现AOP

同样是上面的需求,我们假设并没有继承的接口,这我们可以使用cglib来实现。

首先我们重新定义一个UserDaoImpl2,它不会实现任何接口:

1 public classUserDaoImpl22 {3 privateString name;4

5 public void save() throwsInterruptedException {6 Thread.sleep(3000);7 System.out.println("save() is called for " +name);8 }9

10 public voidsetName(String name) {11 this.name =name;12 }13

14 publicString getName() {15 returnname;16 }17

18 public voidraiseException()19 {20 throw new RuntimeException("This is test.");21 }22 }

然后是创建CglibFactory:

1 public class CglibFactory implementsMethodInterceptor2 {3 privateObject target;4 publicObject createUserDao(Object target)5 {6 this.target =target;7 Enhancer enhancer = newEnhancer();8 enhancer.setSuperclass(target.getClass());9 enhancer.setCallback(this);10 returnenhancer.create();11 }12

13 publicObject intercept(Object proxy, Method method, Object[] args,14 MethodProxy methodProxy) throwsThrowable {15 UserDaoImpl2 userDao =(UserDaoImpl2)target;16 if (userDao.getName() != null)17 {18 returnmethod.invoke(target, args);19 }20 else

21 {22 System.out.println("The name is null.");23 }24 return null;25 }26 }

它实现了MethodInterceptor接口,其中包括intercept方法,这个方法就会通过反射的方式来触发目标方法,同时还可以添加一些其他处理。

下面是测试方法:

1 private static void test2() throwsInterruptedException2 {3 CglibFactory cf = newCglibFactory();4 UserDaoImpl2 temp = newUserDaoImpl2();5 UserDaoImpl2 userDao =(UserDaoImpl2)cf.createUserDao(temp);6 userDao.save();7 temp.setName("Zhang San");8 userDao =(UserDaoImpl2)cf.createUserDao(temp);9 userDao.save();10 }

输出结果如下:

The name is null.

save() is calledfor Zhang San

使用Spring实现AOP

Spring框架集合了ProxyFactory和Cglib两种方式来实现AOP。

我们来看一个示例,还是使用上面定义的UserDaoImpl以及UserDaoImpl2。

首先需要定义一个interceptor:

1 @Aspect2 public classMyInterceptor {3

4 @Pointcut("execution (* sample.spring.aop.*.*(..))")5 public voidanyMethod(){}6

7 @Before("anyMethod()")8 public voidbefore()9 {10 System.out.println("Before");11 }12

13 @After("anyMethod()")14 public voidafter()15 {16 System.out.println("After");17 }18

19 @Around("anyMethod()")20 public void Around(ProceedingJoinPoint pjp) throwsThrowable21 {22 long start =System.currentTimeMillis();23 pjp.proceed();24 long end =System.currentTimeMillis();25 System.out.println("执行时间:" + (end -start));26 }27

28 @Before("anyMethod() && args(name)")29 public voidbefore(String name)30 {31 System.out.println("The name is " +name);32 }33

34 @AfterReturning(pointcut="anyMethod()", returning="result")35 public voidafterReturning(String result)36 {37 System.out.println("The value is " +result);38 }39

40 @AfterThrowing(pointcut="anyMethod()", throwing="e")41 public voidafterThrowing(Exception e)42 {43 e.printStackTrace();44 }45 }

我们可以看到上面的代码中包含了一些Annotation,这些Annotation是用来实现AOP的关键。

然后需要修改beans.xml,添加如下内容:

1

2

3

4

其中第一行是让Spring打开AOP的功能,下面三行定义了三个bean,这里我们把interceptor也看做是一个bean对象。

接下来是测试代码:

1 private static void test3() throwsInterruptedException2 {3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/aop/beans.xml");4 UserDao userDao = (UserDao)ctx.getBean("userDaoImpl");5 userDao.save();6 UserDaoImpl2 userDao2 = (UserDaoImpl2)ctx.getBean("userDaoImpl2");7 userDao2.save();8 userDao2.setName("Zhang San");9 String name =userDao2.getName();10 //userDao2.raiseException();

11 }

这里我们可以看到,测试方法中既使用了UserDaoImpl1(这里是UserDao接口),也是用了UserDaoImpl2。正如我们上面所言, 在Spring中,如果类实现了接口,Spring会按照ProxyFactory的方式来处理;如果没有实现接口,Spring会按照Cglib的方式 来处理。

上面测试方法的输出如下:

Before

Before

save() is calledfor null执行时间:1The value isnullAfter

After

执行时间:1The value isnullBefore

Before

save() is calledfor null执行时间:3001The value isnullAfter

After

执行时间:3002The value isnullBefore

The name is Zhang San

Before

执行时间:26The value isnullAfter

After

执行时间:27The value isnullBefore

Before

执行时间:0The value isnullAfter

After

执行时间:1The value isnull

使用Spring配置文件来配置AOP

上面的示例中,我们使用Annotation来配置AOP的信息,同样我们也可以使用xml文件的方式来配置AOP。

还是以上面定义的interceptor为基础,我们去掉里面所有的Annotation,然后在beans.xml中添加如下内容:

1

2

3

4

5

6

7

8

9

10

11

测试方法和输出结果同上。

Spring和JDBC

Spring中也包含了对JDBC数据访问的支持,它有一个JdbcTemplate的机制,其中提供了大量的API,对ResultSet进行了封装,可以大大简化我们的工作量。

同时Spring还提供了针对事务的支持,包含了一些Annotation,既可以作用在类上,也可以作用在方法上。

下面是一个简单的示例,我们还是连接MySQL数据库中的user表,实现对其CRUD操作。

首先是定义业务对象以及DAO接口:

1 public classUser {2

3 private intuserID;4 privateString userName;5 public void setUserID(intuserID) {6 this.userID =userID;7 }8 public intgetUserID() {9 returnuserID;10 }11 public voidsetUserName(String userName) {12 this.userName =userName;13 }14 publicString getUserName() {15 returnuserName;16 }17 }18

19 public interfaceUserDao {20

21 voidinsertUser(User user);22 voidupdateUser(User user);23 voiddeleteUser(User user);24 ListgetAllUser();25 User getUser(intid);26 }

然后是建立一个Dao的实现类,这里使用了一些JdbcTemplate API:

1 @Transactional2 public class UserDaoImpl implementsUserDao3 {4 privateJdbcTemplate jdbcTemplate;5

6 public void setDataSource(DataSource dataSource) throwsSQLException7 {8 jdbcTemplate = newJdbcTemplate(dataSource);9 System.out.println(dataSource.getConnection().getMetaData().getDriverName());10 }11

12 public voiddeleteUser(User user) {13 jdbcTemplate.update("delete from user where id=?",14 newObject[]{user.getUserID()},15 new int[]{java.sql.Types.INTEGER});16 }17

18 @SuppressWarnings("unchecked")19 public ListgetAllUser() {20 return (List)jdbcTemplate.query("select * from user",21 newRowMapper()22 {23 public Object mapRow(ResultSet rs, int arg) throwsSQLException24 {25 User user = newUser();26 user.setUserID(rs.getInt("ID"));27 user.setUserName(rs.getString("NAME"));28

29 returnuser;30 }31 });32 }33

34 public User getUser(intid) {35 try

36 {37 return (User)jdbcTemplate.queryForObject("select * from user where id=?",38 newObject[]{id},39 new int[]{java.sql.Types.INTEGER},40 newRowMapper()41 {42 public Object mapRow(ResultSet rs, int arg) throwsSQLException43 {44 User user = newUser();45 user.setUserID(rs.getInt("id"));46 user.setUserName(rs.getString("name"));47 returnuser;48 }49 });50 }51 catch(Exception ex)52 {53 System.out.println(ex.getMessage());54 }55 return null;56

57 }58

59 public voidinsertUser(User user) {60 jdbcTemplate.update("insert into user (id,name) values(?,?)",61 newObject[]{user.getUserID(), user.getUserName()},62 new int[]{java.sql.Types.INTEGER, java.sql.Types.VARCHAR});63 }64

65 public voidupdateUser(User user) {66 jdbcTemplate.update("update user set name=? where id=?",67 newObject[]{user.getUserName(), user.getUserID()},68 new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});69 }70

71 }

JdbcTemplate还提供了一些其他的API,也非常实用。

接下来需要修改beans.xml:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

这里theDataSource用来配置数据库连接信息;txManager来配置事务管理器的信息;userDao是我们的Dao实现类信息。

下面是测试方法:

1 public static voidtest1()2 {3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/jdbc/beans.xml");4 UserDao userDao = (UserDao)ctx.getBean("userDao");5 System.out.println("=====get all user=====");6 List users =userDao.getAllUser();7 for(User user:users)8 {9 System.out.println("ID:" + user.getUserID() + ";Name:" +user.getUserName());10 }11 System.out.println("=====insert user=====");12 User user = newUser();13 user.setUserID(10);14 user.setUserName("Zhang Fei");15 userDao.insertUser(user);16 user = userDao.getUser(10);17 System.out.println("ID:" + user.getUserID() + ";Name:" +user.getUserName());18 System.out.println("=====update user=====");19 user.setUserName("Devil");20 userDao.updateUser(user);21 user = userDao.getUser(10);22 System.out.println("ID:" + user.getUserID() + ";Name:" +user.getUserName());23 System.out.println("=====delete user=====");24 userDao.deleteUser(user);25 user = userDao.getUser(10);26 if (user == null)27 {28 System.out.println("delete successfully.");29 }30 }

输出结果如下:

MySQL-AB JDBC Driver=====get all user=====ID:1;Name:Zhang San

ID:2;Name:TEST=====insert user=====ID:10;Name:Zhang Fei=====update user=====ID:10;Name:Devil=====delete user=====Incorrect result size: expected1, actual 0delete successfully.

说到数据库事务,我们在上面的UserDaoImpl中可以看到,这个类的前面有一个名为@Transcational的Annotation声明,这是Spring实现事务的关键点,它既可以作用在类上,也可以作用在方法上。

@Transactional包含以下参数:

propagation参 数,Propagation类型(枚举),默认值为Propogation.REQUIRED,支持的值有REQUIRED、MANDATORY、 NESTED、NEVER、NOT_SUPPORTED、REQUIRE_NEW、SUPPORTS。

isolation参数,Isolation类型(枚举),默认值为Isolation.DEFAULT,支持的值有DEFAULT、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。

timeout参数,int类型,事务的超时时间,默认值为-1,即不会超时。

readOnly参数,boolean类型,true表示事务为只读,默认值为false。

rollbackFor参数,Class extends Throwable>[]类型,默认为空数组。

rollbackForClassName参数,String[]类型,默认为空数组。

noRollbackFor参数,Class extends Throwable>[]类型,默认为空数组。

noRollbackForClassName参数,String[]类型,默认为空数组。

java中sping基础_Java回顾之Spring基础相关推荐

  1. Java回顾之Spring基础

    这一篇主要讲Spring一些基础的内容. 概述 Spring 是一个非常火的框架,尤其是在Web开发领域,和Struts以及Hibernate构成了SSH三剑客.当时Web开发的另一个组合是LAMP, ...

  2. 5 java中的集合类_java基础(5)-集合类1

    集合的由来 数组是很常用的一种数据结构,但假如我们遇到以下这样的的问题: 容器长度不确定 能自动排序 存储以键值对方式的数据 如果遇到这样的情况,数组就比较难满足了,所以也就有了一种与数组类似的数据结 ...

  3. java中循环语句_Java语法基础之循环结构语句详解

    一.循环结构 循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体语句,当反复执行这个循环体时,需要在合适的时候把循环判断条件修改为false,从而结束循环,否则循 ...

  4. Java中introduce方法_Java基础—继承

    继承是面向对象的核心特征之一,是由已有类创建新类的机制.利用继承机制,可以先创建一个具有共性的一般类,然后根据该一般类创建具有特殊性的新类,新类继承一般类的属性和方法,并根据需要增加自己的新属性和方法 ...

  5. 圆的周长在java中怎么表示_Java基础之计算圆的周长

    最简单的程序 圆形的周长公式: C=πd=2πr π是圆周率,约等于3.14,公式中r为圆的半径,d为圆的直径 在数学领域,称之为公式,在计算机领域,习惯称之为算法. 算法描述的是,如果要解决一个问题 ...

  6. java web应用开发_Java Web应用开发基础

    模块1 Java Web应用开发概述 1.1 Web基础知识 1.1.1 Web应用及其开发 1.1.2 动态网页 1.1.3 B/S结构 1.1.4 JSP简介 1.2 创建第一个Web项目 1.2 ...

  7. java 01 02_Java知识系统回顾整理01基础02面向对象01类和对象

    一.面向对象实例--设计英雄这个类 LOL有很多英雄,比如盲僧,团战可以输,提莫必须死,盖伦,琴女 所有这些英雄,都有一些共同的状态 比如,他们都有名字,hp,护甲,移动速度等等 这样我们就可以设计一 ...

  8. java中怪物移动_java中两大怪物,附带面试题!

    最近老是有小伙伴问类和Object相关的问题,感觉还是很多人对此不是很明白,那我们今天就干掉这两个怪物. 类介绍 Java 程序是由若干个类组成的,类也是面向对象编程思想的具体实现. 以下为类的定义: ...

  9. java中的文件_JAVA中文件的操作

    在java中,对文件(例如图片)进行操作,包括上传.修改.删除 一,文件上传 1.文件传到哪里,不仅可以保存在数据库中,也可以上传到远程服务器,文件保存的是文件的路径 2.文件上传都需要做什么?写那些 ...

最新文章

  1. TimeQuest之delay_fall clock_fall傻傻分不清楚
  2. 网工路由基础(6)BGP协议
  3. PrimerCH3字符串,向量,迭代器,数组
  4. form表单,submit,ajax提交
  5. 逻辑性不好可以学python吗_如果本文若未能让你学会“Python”,可能真的不适合学习Python...
  6. QtCreator下使用c++标准输入cin输出cout没有阻塞等待输入
  7. react入门jsx
  8. linux编译静态库的头文件,条件编译,头文件,静态库,共享库与多文件编程
  9. nextcloud+nginx+mysql_nextcloud网盘搭建:Ubuntu18.04+Nginx+Mysql
  10. Linux的ping用python,python与linux中的非特权ping IPPROTO_ICMP
  11. html写樱花树,写樱花树的作文
  12. 干货 | 教你打造一款颜值逆天的VS Code
  13. Requirement already satisfied问题
  14. Windows下,文件(夹)选择/打开对话框的三种创建方式
  15. php将json转化成数组,php如何把json转换成数组
  16. 为什么说vivo S7才是5G轻薄旗舰的正确打开方式
  17. IT职场人生系列之二十三:知识体系(专家与杂家)
  18. WCF双工通信单工通信
  19. 初次组装台式机-618自营-装机配置单-3000价位中上普通家用型主机
  20. 中英字体混和排版的图片获取流程

热门文章

  1. 7.2Python入门(三)
  2. pc和移动端获取滚动条的位置
  3. 浅谈CDQ分治与偏序问题
  4. php中浮点数计算问题
  5. 第一阶段冲刺(第五天)
  6. Qt-连续容器及迭代器
  7. 硬盘分区表和文件分配表格式
  8. jquery remove()不兼容问题解决方案
  9. laravel5集成支付宝alipay扫码支付流程(Laravel 支付解决方案)
  10. 清华大学崔鹏:因果推断技术最新的发展趋势及在推荐系统中的应用