144 SSM与SSH

一、SSM说明

ssm(Spring、SpringMVC、mybatis)整合:

  1. 配置文件的整合:SpringMVC的配置文件(mvc.xml)单独一个、Spring的配置文件(applicationContext.xml)与mybatis的配置文件(mybatis-config.xml)可以选择整合成一个,也可以选择保留mybatis-config.xml,只不过其里面的数据源配置,mapper文件注册等要在applicationContext.xml里面写,仅仅保留一些< settings> < plugin>标签,不过还是建议整合成一个,

  2. mvc.xml 与 applicationContext.xml 中的关于 注解扫描 的配置

    1. 两个工厂不能有彼此侵入,即,生产的组件不能有重合。
    2. 告知SpringMVC 哪些包中 存在被注解的类
      use-default-filters=true凡是被@Controller @Service @Repository注解的类, 都会被扫描,
      use- default- filters=false默认不扫描包内的任何类,只扫描include- filter中指定的类,只扫描被@Controller注解的类
    3. mvc.xml :
    <!-- 注解扫描  下面这些配置是指SpringMVC在扫描com.wlw包下的注解时,只扫描有Controller注解的类(就是类名之上加了@Controller的类),其他的忽略-->
    <context:component-scan base-package="com.wlw" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:include-filter>
    </context:component-scan>

​ 4. applicationContext.xml

    <!--扫描注解 下面这些配置是指Spring在扫描com.wlw包下的注解时,不扫描有Controller注解的类(就是类名之上加了@Controller的类,因为这样的类被SpringMVC扫描了,区分职责关系,可以对比mvc.xml文件),其他的都要扫描-->

<context:component-scan base-package="com.wlw" use-default-filters="true">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
  1. 整个项目有大致三个配置文件 web.xml 、 mvc.xml (SpringMVC配置文件)、 applicationContext.xml (Spring配置文件), 在web.xml文件中会声明另外两个配置文件地址,当tomcat启动时,会加载web.xml文件,进而加载另外两个配置文件,创建springmvc工厂(子工厂)与spring工厂(父工厂);

  2. xml配置文件与注解之间的选择:在我们自己写的代码中,service层(xxxServiceImpl)用注解(@Service)来声明bean、用注解(@Autowired @Qualifier(“userDao”))来自动注入dao、用注解(@Transactional 来配置事务); controller层使用注解(@Controller)来声明bean、用注解(@Autowired @Qualifier(“userServiceImpl”))来自动注入 service。

  3. SpringMVC配置文件(mvc.xml)中写的是:开启注解扫描、注解驱动、视图解析器、静态资源访问、拦截器、异常解析器、文件上传解析器等

  4. Spring配置文件(applicationContext.xml)中写的是: DataSource、SqlSessionFactory、DAO接口 MapperScannerConfigurer、扫描注解、事务管理器、开启事务注解等 (其中之前在mybatis所作的配置,是写在SqlSessionFactory这个bean中的)

二、实践:

  • 第一步:在 pom.xml文件中导入依赖,声明打包方式,更改maven编译规则,让xxxMapper.xml文件可以被编译,之后再第一次运行时,可查看target/classes文件中是否有对应的xxxMapper.xml,看是否编译成功

  • 第二步:在main文件下新建webapp文件夹,在webapp文件下新建WEB-INF文件夹,并在WEB-INF文件夹下新建web.xml文件,这是web项目的配置文件,随着tomcat服务器启动而被加载,里面配置基本都是servlet组件,基本包括SpringMVC工厂(前端(核心)控制器)和Spring工厂,以及对post请求中,中文参数乱码的处理;并且项目的前端页面组件放在webapp文件夹下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- SpringMVC前端(核心)控制器
         1. 前端,接收所有请求
         2. 启动SpringMVC工厂  mvc.xml
         3. 负责springMVC流程调度
    -->
    <servlet>
        <servlet-name>mvc_wlw</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 局部参数,声明mvc配置文件位置-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:mvc.xml</param-value>
        </init-param>
        <!-- 懒汉式  饿汉式加载  可选-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc_wlw</servlet-name>
        <url-pattern>/</url-pattern>
        <!--<url-pattern>*.action</url-pattern>-->
    </servlet-mapping>

    <!-- 此过滤器会进行:request.setCharactorEncoding("utf-8");  对post请求中,中文参数乱码有效-->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 启动Spring工厂 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
</web-app>
  • 第三步:在src/main/resources写mvc.xml 与 applicationContext.xml;
    • mvc.xml
    • applicationContext.xml
<beans 	xmlns="http://www.springframework.org/schema/beans"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:mvc="http://www.springframework.org/schema/mvc"
          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
							http://www.springframework.org/schema/context
							http://www.springframework.org/schema/context/spring-context.xsd
							http://www.springframework.org/schema/mvc
							http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 注解扫描  下面这些配置是指SpringMVC在扫描com.wlw包下的注解时,只扫描有Controller注解的类(就是类名之上加了@Controller的类),其他的忽略-->
    <context:component-scan base-package="com.wlw" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:include-filter>
    </context:component-scan>

    <!-- 注解驱动 -->
    <mvc:annotation-driven>
        <!-- 安装FastJson,转换器 -->
        <mvc:message-converters>
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <!-- 声明转换类型:json (将java对象转成josn)-->
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!-- 视图解析器
        作用:1.捕获后端控制器的返回值="hello"
             2.解析: 在返回值的前后 拼接 ==> "/hello.jsp"
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/"></property>
        <!-- 后缀 -->
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 处理静态资源访问-->
    <mvc:default-servlet-handler/>

    <!--拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/loger/test1"/> <!--要拦截的路径-->
            <bean class="com.wlw.interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

    <!--异常解析器-->
    <bean class="com.wlw.resolver.MyExceptionResolver"/>

    <!--文件上传解析器-->
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--整合时,DAO放在工厂中(bean标签)是由MapperScannerConfigurer 来帮我们完成的 ,
        而MapperScannerConfigurer 又需要sqlSessionFactory支持 , sqlSessionFactory 又需要DataSource-->

    <!-- DataSource -->
    <!-- 导入文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--创建数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--基本配置-->
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>

        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="${jdbc.init}"/>
        <property name="minIdle" value="${jdbc.minIdle}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>

        <!-- 配置获取连接等待超时的时间 ms-->
        <property name="maxWait" value="60000"/>

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>
    </bean>

    <!-- SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入连接池 -->
        <property name="dataSource" ref="dataSource"></property>
        <!-- (注册xxxDao-mapper文件)注入dao-mapper文件信息,如果映射文件和dao接口 同包且同名,则此配置可省略(要注意因为把mapper文件放在了dao文件夹下,所以要在pom.xml中更改maven编译规则)-->
        <property name="mapperLocations">
            <list>
                <value>classpath:com/wlw/dao/*.xml</value>
            </list>
        </property>
        <!-- 为实体类起别名 -->
        <property name="typeAliasesPackage" value="com.wlw.entity"></property>

        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            <!-- 页号 调整到合理的值  0  max -->
                            <prop key="reasonable">true</prop>
                        </props>
                    </property>
                </bean>
            </array>
        </property>
    </bean>

    <!-- DAO接口 MapperScannerConfigurer-->
    <!-- mapperScannerConfigurer  管理DAO实现类的创建,并创建DAO对象,存入工厂管理,当执行完这个配置之后,在工厂中就会有一个id为userDAO 的bean,而这个bean就是UserDAO实现类的对象 -->
    <bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- dao接口所在的包  如果有多个包,可以用逗号或分号分隔 <property name="basePackage" value="com.a.dao,com.b.dao"></property>-->
        <property name="basePackage" value="com.wlw.dao"></property>
        <!-- 如果工厂中只有一个SqlSessionFactory的bean,此配置可省略 -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

    <!--扫描注解 下面这些配置是指Spring在扫描com.wlw包下的注解时,不扫描有Controller注解的类(就是类名之上加了@Controller的类,因为这样的类被SpringMVC扫描了,区分职责关系,可以对比mvc.xml文件),其他的都要扫描-->
    <context:component-scan base-package="com.wlw" use-default-filters="true">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 1. 引入一个事务管理器,其中依赖DataSource,借以获得连接,进而控制事务逻辑 -->
    <bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--开启事务注解  只针对 这个@Transactional 事务注解-->
    <tx:annotation-driven transaction-manager="tx"/>
</beans>

三、项目目录

D:\Program Files\IDEAworkspace\projects\JavaWeb_high\SSM_exam01

在这里插入图片描述

SSM与SSH

MyBatis与Hibernate的优劣

  • 无论MyBatis或Hibernate都可以被称为ORM框架,Hibernate的设计理念是面向POJO的,而MyBatis不是。

  • Hibernate是一个标准的ORM框架,基本不需要编写SQL就可以通过映射关系来操作数据库,是一种全表映射的体现,维护关系比较复杂,sql语句自己生成,这就造成了对sql语句优化,修改比较困难。;而MyBatis需要我们提供SQL语句去运行,这就对sql修改和优化非常容易实现,程序员不必精通sql,只要懂得操作POJO就能够操作对应数据库的表。

  • 在之前的时候,管理系统时代,首先是实现业务逻辑,然后才是性能,所以Hibernate在当时是主流。;而现在在移动互联网时代,MyBatis是首选,不屏蔽SQL,程序员可以自己制定SQL规则,能更加精确定义SQL,从而优化性能。更符合移动互联网高并发,大数据,高性能,高响应的要求。

  • Hibernate和MyBatis的增、删、查、改,对于业务逻辑层来说大同小异,对映射而言Hibernate的配置不需要接口和SQL,而MyBatis是需要的。对于Hibernate而言,不需要编写大量的SQL,就可以完全映射,同时提供了日志、缓存、级联(级联比MyBatis强大)等特性,此外还提供HQL (Hibernate Query Language)对POIO进行操作,使用十分方便,但是它也有**致命的缺陷:**由于无须SQL,当多表关联超过3个的时候,通过Hibernate的级联会造成太多性能的丢失,又或者我现在访问一个财 务的表,然后它会关联财产信息表,财产又分为机械、原料等.显然机械和原料的字段是不一样的,这样关联字段只能根据特定的条件 变化而变化,而Hibernate无法支持这样的变化。遇到存储过程,Hibernate只能作罢。更为关键的是性能,在管理系统的时代,对于性能的要求不是那么苛刻,但是在互联网时代性能就是系统的根本,响应过慢就会丧失客户,试想一下谁会去用一个经常需要等待超过10 秒以上的应用呢? **以上的问题MyBatis都可以解决,MyBatis 可以自由书写SQL、支持动态SQL、处理列表、动态生成表名,支持存储过程。**这样就可以灵活地定义查询语句,满足各类需求和性能优化的需要,这些在互联网系统中是十分重要的。

  • 但MyBatis也有缺陷。首先,它要编写SQL和映射规则,其工作量稍微大于 Hibernate.其次,它支持的工具也很有限,不能像Hibernate那样有许多的插件可以帮助生成映射代码和关联关系,而即使使用生成工具,往往也需要开发者进一步简化, MyBatis 通过手工编码,工作量相对大些。

  • 使用环境:对于性能要求不太苛刻的系统,比如管理系统、ERP 等推荐使用Hibernate;而对于性能要求高、响应快、灵活的系统则推荐使用MyBatis.

  • 总1:

    • Hibernate:
      • 优点:面向对象开发,不需要自己写sql语句。如果进行数据库迁移不需要修改sql语句,只需要修改一下方言。使用方便
      • 缺点:hibernate维护数据表关系比较复杂。完全是有hibernate来管理数据表的关系,不易维护,不易优化,不能开发比较复杂的业务。不容易写出高性能的程序。
      • 适合范围:适合需求固定,对象数据模型稳定,性能要求不太苛刻的系统,中小型项目,比如:企业OA系统,管理系统
    • MyBatis:
      • 优点:对sql的优化,修改比较容易,可以灵活地定义查询语句,满足各类需求和性能优化的需要
      • 缺点:工作量大,大型复杂系统需要写很多的sql语句
      • 适合范围:适合开发需求变更频繁的系统,比如:互联网项目。
  • 总2:

    • 两者的相同点

      • Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。

      • Hibernate和MyBatis都支持JDBC和JTA事务处理。

    • 两者各自优势

      • MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
      • MyBatis容易掌握,而Hibernate门槛较高。
      • Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
      • Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
      • Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
      • Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳,更新操作不能指定刷新指定记录,会清空整个表,但是也可以使用第三方缓存。
      • Hibernate 封装性好,屏蔽了数据库差异,自动生成SQL语句,应对数据库变化能力较弱,SQL语句优化困难。
      • MyBatis仅实现了SQL语句和对象的映射,需要针对具体的数据库写SQL语句,应对数据库变化能力较强,SQL语句优化较为方便。

SH和SSM对比异同点、各自优势

SSH和SSM定义

  • SSH 通常指的是 Struts2 做控制器(Action),Spring 管理各层的组件,Hibernate 负责持久化层。

  • SSM 则指的是 SpringMVC 做控制器(controller),Spring 管理各层的组件,MyBatis 负责持久化层。

共同点:

1.Spring依赖注入DI来管理各层的组件。

2.使用面向切面编程AOP管理事物、日志、权限等。

不同点:

1.Struts2 和 SpringMVC 控制器(controller)控制视图和模型的交互机制的不同,

2.Struts2是Action类级别,SpringMVC是方法级别,更容易实现RESTful风格。

SSH和SSM的实现原理

Struts2 的实现原理

在这里插入图片描述

Struts2框架执行步骤(Struts2使用Filter嵌入):

1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求

2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助

3、接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action

4、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy

5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类

6、ActionProxy创建一个ActionInvocation的实例。

7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。

8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。

9、将处理结果返回给客户端

SpringMVC 的实现原理:

在这里插入图片描述

SpringMVC框架执行步骤(SpringMVC使用Servlet嵌入):

1、客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.

2、DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)。

3-4、DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。

5、Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet。

6、Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。

7、Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。

总结

SSM和SSH不同主要在MVC实现方式,以及ORM持久化方面不同(Hiibernate与Mybatis)。SSM越来越轻量级配置,将注解开发发挥到极致,且ORM实现更加灵活,SQL优化更简便;而SSH较注重配置开发,其中的Hiibernate对JDBC的完整封装更面向对象,对增删改查的数据维护更自动化,但SQL优化方面较弱,且入门门槛稍高。

Spring家族:

在这里插入图片描述

      掌握基于腾讯人工智能(AI)的车牌识别技术,使用车牌识别技术实现一个完整的停车场管理系统,项目包括网页调用摄像头拍照,车牌拍照识别,上传车牌图片识别,用户管理,车辆管理(临时车与包月车),车辆出场,入场管理,停车费收费管理,按照临时车或包月车自动计算停车费,系统参数设置,修改用户密码及安全退出等功能,该系统采用Jsp技术,使用SSM框架,Mysql数据库,ajax技术及人工智能等相关技术实现。 项目开发技术:java,jsp,mysql,MyBatis,SpringMVC,jquery,ajax,json 项目运行环境:jdk1.7及以上版本,tomcat6.0及以上版本,mysql5.5及以上版本 项目开发工具: 本项目开发工具是Eclipse,也支持myEclipse,Intellij Idea等其他版本开发工具 相关课程学习顺序 本校课程是培养JAVA软件工程师及JSP WEB网络应用程序开发,android工程师的全套课程,课程学习顺序如下: JAVA初级工程师:     1、计算机基础     2、HTML语言基础     3、C语言从入门到精通+贪吃蛇游戏     4、贪吃蛇游戏     5、SQL SERVER数据库基础     6、JAVA从入门到精通+推箱子游戏+QQ即时通讯软件     7、推箱子游戏;     8、仿QQ即时通讯软件; JAVA中级工程师:     9、SQLSERVER数据库高级     10、SQLSERVER从入门到精通(基础+高级)               11、JavaScript从入门到精通,     12、JSP从入门到精通+点餐系统,     13、JSP从入门到精通+在线视频学习教育平台,     14、JSP从入门到精通+大型电商平台;     15、XML从入门到精通,     16、数据结构(JAVA版), JAVA高级工程师:     17、Oracle数据库从入门到精通,     18、ajax+jquery从入门到精通,     19、EasyUI从入门到精通, SSH框架:     20、Struts2从入门到精通课程,     21、Hibernate从入门到精通课程,     22、Spring从入门到精通课程;     23、Echarts从入门到精通,     24、Excel基于POI的导入导出 工作流框架:     25、Activiti流程框架从入门到精通     26、JBPM流程框架从入门到精通 SSM框架:     27、MyBatis从入门到精通     28、Spring MVC从入门到精通 面试题:     29、职业生涯规划及面试题集锦 商业项目:     30、微信公众号在线支付系统     31、微信生活缴费在线支付系统     32、支付宝生活缴费在线支付系统     33、在线考试系统     34、手机订餐管理系统,     35、CRM客户关系管理系统     36、大型房地产CRM销售管理系统     37、CMPP2,CMPP3移动网关系统 人工智能:     38、人脸识别在线考试系统     39、人脸识别系统项目实战     40、车牌识别系统项目实战     41、身份证识别系统项目实战     42、营业执照识别系统项目实战           43、名片识别管理系统
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页