首页 > 编程语言 >java—Spring框架

java—Spring框架

时间:2024-07-11 18:27:08浏览次数:13  
标签:java 框架 spring Spring flash User org import public

Spring

简介

        Spring框架由Rod Johnson开发,2004年发布了Spring框架的第一版。Spring是一个从实际开发中抽取出来的框架,因此它完成了大量开发中的通用步骤,留给开发者的仅仅是与特定应用相关的部分,从而大大提高了企业应用的开发效率。

Spring是什么?

        Spring是一个轻量级的,IoC和AOP的一站式java开发框架,是为了简化企业级应用开发而生。

名词解释:
        轻量级:Spring框架所使用的jar都比较小,Spring核心功能的所需的jar总共在3M左右。Spring框架运行占用的资源少。
        IoC(Inverse of Control):控制反转。当我们需要使用某一个对象的方法时,在传统模式下有两种方式:①原始做法:主动创建该对象;②简单工厂模式:找到该对象所在工厂,主动通过工厂获取该对象。
        传统的方法描述中都有“主动”,也就是在编写代码时,开发者必须要显现的获取该对象,这样做有两大缺点,高耦合度,并且在后期对项目的升级维护。而使用了Spring框架后,IoC很巧妙的解决了这一问题,可以将所需要的对象交由Spring框架创建管理,我们在哪里使用,在哪里定义一个接收的容器即可。由于对象由开发者管理变更为由Spring框架管理,所以称之为控制反转。
        AOP(Aspect Orient Programming):AOP也就是面向切面编程(一种编程思想),作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。其实AOP问世的时间并不太长,AOP和OOP互为补充,面向切面编程将程序运行过程分解成各个切面。AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。    简单讲就是可以为程序动态的添加某种功能,而不需要修改原来的代码。如对数据库修改需要提交事务、打印日志文件等。

此处并不需要担心对IoC和AOP不理解。下面对IoC和AOP进一步解释

案例演示

IoC:

IoC(控制反转):IoC不是一项技术,而是一种设计思想,将原来在程序中手动创建对象的控制权交由Spring框架来管理。IoC容器负责对象的实例化、对象的初始化、对象和对象之间的依赖关系、对象的销毁,对象提供对象的查找等操作,对象的整个生命周期都是由容器来控制的。当我们需要使用的时候直接从IoC容器中获取即可,我们只需要定义一个对象容器。

Demo前提,创建一个maven项目
        导入spring框架所需依赖:

    <!-- spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>

Spring Bean管理:

基于xml文件配置方式

在resources目录下创建spring配置文件spring.xml
创建方式如图所示:

spring.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:配置需要Spring管理的类
    id:生成的对象名称
    class:类全名
    name:对象别名, 可以定义多个
    scope:singleton(默认值):在Spring中只存在一个bean实例, 即单例模式
          prototype:原型, getBean()时每次都会创建一个新的对象, 即多例模式
    -->
    <bean id="user" name="user2,user3" class="com.flash.demo.model.User" scope="prototype"/>
</beans>
创建用户类:
package com.flash.demo.model;

/**
 * @author flash
 * @date 2024/07/11 10:14
 * 功能描述:用户类
 */
public class User {
    private Integer id;
    private String name;
    private Integer age;

    // 无参构造器
    public User() {
        System.out.println("User无参构造器");
    }

    public User(Integer id, String name, Integer age) {
        System.out.println("User三参构造器");
        this.id = id;
        this.name = name;
        this.age = age;
    }

    // 由于框架要使用类反射, 所以在创建类时, 将对应的属性的getter和seter方法生成, 类反射会用到
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
        System.out.println("setId被调用");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Test测试类:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author flash
 * @date 2024/07/11 10:16
 * 功能描述:获取Spring框架生成的User对象
 */
public class Test1 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Object user = applicationContext.getBean("user");
        System.out.println(user);
        System.out.println("user的hash值 = " + user.hashCode());
        Object user2 = applicationContext.getBean("user2");
        System.out.println("user2的hash值 = " + user2.hashCode());
    }
}

当spring.xml文件中User类scope = singleton时运行结果:

当spring.xml文件中User类scope = prototype时运行结果:

对象初始化:

以下演示scope均使用默认的单例模式

方式1(setter方法):

spring.xml更改:

    <bean id="user" name="user2,user3" class="com.flash.demo.model.User">
        <property name="id" value="1"/>
        <property name="name" value="张三"/>
        <property name="age" value="21"/>
    </bean>

该方式会调用无参构造器创建一个对象实例,然后调用该对象的setter方法完成初始化
运行结果如果所示:

方式2(构造器):

spring.xml更改:

    <bean id="user" name="user2,user3" class="com.flash.demo.model.User" scope="prototype">
        <constructor-arg name="id" value="1"/>
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="21"/>
    </bean>

该方式会调用此处定义的三个参数的构造器创建一个对象实例
运行结果如果所示:

基于注解方式
开启注解扫描

采用注解的方式实现IoC需要开启注解扫描,spring.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: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/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启注解扫描, 检测添加有 spring 注解标签的类-->
    <context:component-scan base-package="com.flash.demo"/>
</beans>
为User类添加注解

测试类:
import com.flash.demo.model.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author flash
 * @date 2024/07/11 10:16
 * 功能描述:获取Spring框架生成的User对象, 注解方式
 */
public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = applicationContext.getBean("user", User.class);
        System.out.println(user);
    }
}
运行结果:

数据库交互

Spring实现与数据库(mysql)交互,使用阿里数据源提供的druid(德鲁伊)

与数据库交互所需依赖:

        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

        <!-- spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>

        <!-- 阿里数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

spring.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: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/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启注解扫描, 检测添加有 spring 注解标签的类-->
    <context:component-scan base-package="com.flash.demo"/>
    <!--导入属性文件-->
    <context:property-placeholder location="config.properties"/>

    <!--spring 管理阿里巴巴数据库链接对象-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${uname}"/>
        <property name="password" value="${pwd}"/>
        <property name="maxActive" value="${maxActive}"/>
        <property name="initialSize" value="${initialSize}"/>
    </bean>

    <!--创建 spring 对 jdbc 进行封装的一个 jdbcTemplate,spring框架创建JdbcTemplate实例对象并将druidDataSource数据库连接对象注入到该对象中-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource"/>
    </bean>
</beans>

创建config.properties配置文件

config.properties配置文件内容:

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/demo?serverTimezone=Asia/Shanghai
uname=root
pwd=root
maxActive=20 # 最大连接数
initialSize=5 # 初始连接数

数据库交互层类:

package com.flash.demo.dao;

import com.flash.demo.model.User;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;

/**
 * @author flash
 * @date 2024/07/11 13:36
 * 功能描述:数据库交互
 */
// @Repository(value = "userDao") // 指定对象名, 该对象被注入的地方可以通过对象名寻找此对象
@Repository
public class UserDao {
    @Resource
    public JdbcTemplate jdbcTemplate;

    public void insertUser(User user) {
        System.out.println("添加user");
        jdbcTemplate.execute("INSERT INTO `user`(id,`name`,age) VALUES ('1','张三','21')");
    }
}

Service层类:

package com.flash.demo.service;

import com.flash.demo.dao.UserDao;
import com.flash.demo.model.User;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author flash
 * @date 2024/07/11 13:51
 * 功能描述:
 */
@Service(value = "userService")
public class UserService {
	// @Resource(name = "userDao") 通过对象名查找
    @Resource // 注解中没有指定对象名, 按照对象的类型寻找, 即UserDao
    /*
    	也可以使用@Autowired注解标签, 可以添加在要注入的属性上, 也可以是属性的set方法上, 如果直接添加在属性上, 那么set方法可以需要
    	默认情况加, 要注入的属性对象不能为空. @Autowired(required = true), false则可以为空, 允许为空时在值为空时, 不会报spring的错, 
    	而是因为调用它的方法出现空指针异常.
    	@Qualifier与@Autowired搭配使用, 指定对象名, 可以不要, 会根据属性类型自动寻找
    	@Qualifier和@Autowired使用示例:
    	@Autowired
		@Qualifier(value = "userDao")// 这个可以不要, 自动会找

		需要注意的是:在jdk8中可以使用@Resource注解, 在其他版本中可能无法使用. 就必须使用@Autowired注解标签, @Resource注解是由jdk提供的, 而@Autowired注解是由spring提供的
    */

    UserDao userDao;

    public void save(User user) {
        userDao.insertUser(user);
    }
}

Test类:

import com.flash.demo.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author flash
 * @date 2024/07/11 13:49
 * 功能描述:使用注入方式通过阿里的druid将User对象添加到数据库
 */
public class Test3 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        System.out.println("userService = " + userService);
        userService.save(null);
    }
}

运行结果:

在数据库中我们可以看到数据已经成功添加:

AOP

        AOP(Aspect Oriented Programming):意为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,是java开发中的一个重要内容。利用AOP可以对业务逻辑和非业务逻辑进行隔离,从而使得各部分的耦合度降低,提交代码的复用性,也提高开发效率。
        OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
        AOP则是对业务处理过程中的切面进行提取,面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间的低耦合性的隔离效果。OOP和AOP这两种设计思想在目标上有着本质行的差异。

        使用案例:修改数据库数据事务的提交;打印日志,在程序运行期间将对应的操作通过日志的形式记录下来;权限判断,在执行方法前,判断是否有权限。

AOP的基本概念:

    连接点(Joinpoint):类中可以被增强的方法,这个方法就被称为连接点
    切入点(pointcut):类中有很多方法可以被增强,但实际中只有 add 和 update
    被增了,那么 add 和 update 方法就被称为切入点(实际实现的连接点)
    通知(Advice): 通知是指一个切面在特定的连接点要做的事情(增强的功能)。通
    知分为方法执行前通知,方法执行后通知,环绕通知等. 目标(Target): 代理的目标对象(连接点,切入点所在类)
    代理(Proxy): 向目标对象应用通知时创建的代理对象

代码示例:

为了不和IoC的内容混淆,所以重新创建一个项目为读者演示AOP的功能

AOP所需依赖:
        <!-- AOP相关jar-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>

        <!-- spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>
spring.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启注解扫描, 检测添加有 spring 注解标签的类-->
    <context:component-scan base-package="com.flash.springPro2"/>

    <!--启动 AspectJ 支持-->
    <aop:aspectj-autoproxy/>
</beans>
更改UserDao类的内容

此处示例不需要与数据库交互,打印输出一句话即可。

package com.flash.demo.dao;

import com.flash.demo.model.User;
import org.springframework.stereotype.Repository;

/**
 * @author flash
 * @date 2024/07/11 13:36
 * 功能描述:
 */
@Repository
public class UserDao {
    public void insertUser(User user) {
        System.out.println("添加user");
    }
}
前置通知
编写CommonUtil类:

为UserDao类的insertUser(User user)方法功能增强,编写CommonUtil类:

package com.flash.demo.common;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author flash
 * @date 2024/07/11 15:32
 * 功能描述:
 */
@Component // spring 管理生成 CommonUtil 类的对象
@Aspect // 添加此标签类中的方法就是代理对象要调用的方法
public class CommonUtil {
    // 第一个 * 表示任意返回值,第二个 * 表示UserDao类下的任意方法,括号中的“..”表示该方法的所有重载方法
    @Before("execution(* com.flash.demo.dao.UserDao.*(..))") // ..是因为java中有重载, 表示对该方法名的所有方法均使用
    public void printLog() {
        System.out.println("方法执行成功");
    }
}
Test测试类:
import com.flash.demo.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author flash
 * @date 2024/07/11 15:38
 * 功能描述:AOP测试类
 */
public class Test4 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.save(null);
    }
}
运行结果:

可见在程序运行过程,先执行的是CommonUtil类下我们定义的方法,后执行我们所执行的业务逻辑代码,即添加User。这样的方法称之为前置通知。

以下测试所使用的测试类均相同,即Test4

后置通知
编写CommonUtil类
package com.flash.demo.common;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author flash
 * @date 2024/07/11 15:32
 * 功能描述:
 */
@Component // spring 管理生成 CommonUtil 类的对象
@Aspect // 添加此标签类中的方法就是代理对象要调用的方法
public class CommonUtil {
    @AfterReturning("execution(* com.flash.demo.dao.UserDao.*(..))")
    public void commit() {
        System.out.println("提交事物");
    }
}
运行结果:

使用@AfterReturning定义的后置通知在我们执行的业务逻辑中如果出现异常则不执行,
如果使用@After定义后置通知,则不管是否出现异常都会执行该通知

异常通知
编写CommonUtil类
package com.flash.demo.common;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author flash
 * @date 2024/07/11 15:32
 * 功能描述:
 */
@Component // spring 管理生成 CommonUtil 类的对象
@Aspect // 添加此标签类中的方法就是代理对象要调用的方法
public class CommonUtil {
    @AfterThrowing(value = "execution(* com.flash.demo.dao.UserDao.*(..))", throwing = "e")
    public void printException(Throwable e) {
        System.out.println("出异常了" + e.getMessage());
    }
}
更改UserDao类

为其添加一个异常

package com.flash.demo.dao;

import com.flash.demo.model.User;
import org.springframework.stereotype.Repository;

/**
 * @author flash
 * @date 2024/07/11 13:36
 * 功能描述:
 */
@Repository
public class UserDao {
    public void insertUser(User user) {
        System.out.println("添加user");
        System.out.println(1 / 0);
    }
}
运行结果:

@AfterThrowing异常通知,当业务逻辑代码出现异常时通知

环绕通知
编写CommonUtil类
package com.flash.demo.common;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author flash
 * @date 2024/07/11 15:32
 * 功能描述:
 */
@Component // spring 管理生成 CommonUtil 类的对象
@Aspect // 添加此标签类中的方法就是代理对象要调用的方法
public class CommonUtil {
    @Around("execution(* com.flash.demo.dao.UserDao.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = null;
        try {
            System.out.println("保存日志");
            for (Object arg : joinPoint.getArgs()) {
                System.out.println(arg);
            }
            joinPoint.proceed();// 调用自己的方法, 有参数也可以接收参数
            System.out.println("提交事务");
        } catch (Throwable e) {
            System.out.println("异常" + e.getMessage());
        } finally {
            System.out.println("后置通知");
        }
        System.out.println("无论是否异常均执行");
        // 返回方法调用后的结果
        return null;
    }
}
运行结果:

标签:java,框架,spring,Spring,flash,User,org,import,public
From: https://blog.csdn.net/2301_77713282/article/details/140356047

相关文章

  • Spring Boot项目Jar包加密详解
    目录引言Jar包加密的基础知识为什么需要加密Jar包Jar包加密的基本原理常用的Jar包加密工具ProGuardJavaguardJavaAgentSpringBoot项目Jar包加密实战使用ProGuard对SpringBoot项目进行加密集成Javaguard到SpringBoot项目中通过JavaAgent实现动态加密Jar包加密的......
  • Java中线程池的最佳实践
    一、使用正确的声明方式线程池必须手动通过ThreadPoolExecutor的构造函数来声明,避免使用Executors类创建线程池,会有OOM风险。Executors创建的线程池对象有以下弊端:FixedThreadPool和SingleThreadExecutor使用的是有界阻塞队列LinkedBlockingQueue,任务队列的默认长度和......
  • Java多线程&并发编程(二)
    一、CyclicBarrier、CountDownLatch、Semaphore的区别CyclicBarrier的某个线程运行到某个点上之后,该线程即停止运行,直到所有的线程都到达了这个点,所有线程才重新运行(类似于一个栅栏拦住所有线程直到所有线程到达后在重新执行)CountDownLatch则不是,某线程运行到某个点上之后,......
  • Spring MVC 全面指南:从入门到精通的详细解析
    引言:SpringMVC,作为Spring框架的一个重要模块,为构建Web应用提供了强大的功能和灵活性。无论是初学者还是有一定经验的开发者,掌握SpringMVC都将显著提升你的Web开发技能。本文旨在为初学者提供一个全面且易于理解的学习路径,通过详细的知识点分析和实际案例,帮助你快速上手Sprin......
  • 基于Javaweb在线手机购物商城系统设计与实现
      博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书......
  • 1.Introduction to Spring Web MVC framework
    WebMVCframework文档:22.WebMVCframework(spring.io)概述WebMVC框架(WebModel-View-ControllerFramework)是一种用于构建Web应用程序的软件架构模式。MVC模式将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller)。这种分离有助于组织代码和简化开发......
  • java 生成mapbox-gl 可以直接使用的雪碧图,包含对应json,图片大小无限制自动适配
    1、文件路径配置sprite-path:/home/mapplate/sprite/2、实现类packagecom.shgis.service.impl;/***CreatedbyAdministratoron2021/10/9.*/importcom.alibaba.fastjson.JSONObject;importcom.shgis.config.FileProperties;importcom.shgis.entity.Ebuf......
  • JavaScript 进阶(五)---forEach/map/filterevery/some/includes/reduce的详细用法
    目录1.forEach2.map3.filter4.for...in5.for...of6.every7.some8.includes9.reduce举个例子:使用fliter:使用 map 来筛选并转换数组使用 forEach 来筛选并构建数组总结1.forEach-详解:`forEach`方法对数组的每个元素执行一次提供的函数。这个方......
  • Java毕业设计基于Vue+SpringBoot的高校学生评教系统(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录项目介绍技术介绍项目界面关键代码目录项目介绍当今社会己进入信息社会时代。信息己经受到社会的广泛关注,被看作社会和科学技术发展的三大支柱;材料、能源、信息;。信息是管理的基础,是进行决策的的基本依据。在一个组织里,信息......
  • Java毕业设计基于Vue+SpringBoot的癌症患者交流平台(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录项目介绍技术介绍项目界面关键代码目录项目介绍随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。癌症患者交流平台,主要的模块包括查看首页、轮播图、抗癌故事管理......