• (推荐)(全)集成maven,spring,springmvc,mybaits,ehcache,没有shiro。maven坐标全,xml配置文件全,


    本案例中,集成了maven,spring,springmvc,mybatis,ehcache。除了没有shiro,其他的都算全。maven坐标全,xml配置全。

    一,新建maven工程,Maven里选择webapp的ID,生成后,需要自己手动改webapp的版本由2.3改为2.5,否则jsp的el表达式,不起作用。webapp2.5的文件头为:

    <?xml version="1.0" encoding="UTF-8"?>  
     <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
     version="2.5">  
    </web-app>

    二,导入pom的坐标,在导入c3p0的时候,提示用mchange的那个,不用c3p0->c3p0的。否则启动时,提示c3p0的abstract关闭等等错误。在导入后,eclipse里写全类名,如果没有提示,可以用ctrl+shift+T,打开类对话窗寻找,定位到类后,可以用Ctrl+T,打开继承导航。

    <dependency>
      <groupId>javax.servlet</groupId>
       <artifactId>jstl</artifactId>
       <version>1.2</version>
     </dependency>
    <!-- https://mvnrepository.com/artifact/taglibs/standard -->
    <dependency>
        <groupId>taglibs</groupId>
        <artifactId>standard</artifactId>
        <version>1.1.2</version>
    </dependency>
        
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.3.25.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>
    
    <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.48</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.3</version> </dependency>

    <!-- ehcache的二级缓存,此包加入后,有关联,会自动导入ehcache-core的包和日志包-->

    <dependency>
         <groupId>org.mybatis.caches</groupId>
         <artifactId>mybatis-ehcache</artifactId>
         <version>1.1.0</version>
    </dependency>

     

    三、建立包,

    cn.taotao.bean

    cn.taotao.dao

    cn.taotao.service

    cn.taotao.controller

    然后书写实体类等,bean下写Employee.java类。dao下写接口EmployeeMapper.java接口文件。service下写业务类EmployeeService.java,这个类用@Service注解标识。controller下写EmployeeController控制类,这个类用@Controller类标识。各个类之间的引用关系,用@Autowire注解标识。

    四、编写web.xml文件,此文件头必须改为servlet 2.5规范的。

    有两个部分,一个是引入spring文件的ContextLoaderListener。一个是引入springmvc的springDispatcherServlet,如果这个servlet不写引用地址,可以在WEB-INF目录下建立与此servlet名字加-servlet的xml文件,它自动会加载。在安装了spring插件后,这两个eclipse都有自动生成。

    <?xml version="1.0" encoding="UTF-8"?>  
     <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
     version="2.5">  
       
       <!-- needed for ContextLoaderListener -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
    
        <!-- Bootstraps the root web application context before servlet initialization -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        
        <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
        <servlet>
            <servlet-name>springDispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!-- Map all requests to the DispatcherServlet for handling -->
        <servlet-mapping>
            <servlet-name>springDispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>

    五、编写applicationContext.xml文件,即spring的配置文件

    1.数据源。c3p0 的 ComboPooledDataSource,实例化bean',然后引用4个属性,jdbcUrl,driverClass,user,password。在这里建议用context的property-placeholder,来引入一个properties文件,里面保存着已经写好的配置文件,在bean的property里直接引用。

    2.自动扫描包。<context:compont-scan >在这里,排除掉exclude,这个类所代表的注解 org.springframework.stereotype.Controller,就是说除了@Controller以外,其他的包都扫描。

    3.配置事务。DataSourceTransactionManager,实例化这个类。然后注入属性,引用上面的数据源。开启基于注解的事务,<tx:annotation-driven >他的管理器引用上面的管理器Id

    4.Mybatis的sqlSessionFactoryBean。实例化这个bean,然后配置数据源,配置configlocation,和mapperLocation的位置。

    5.配置一个可以批量执行的sqlsession。org.mybatis.spring.SqlSessionTemplate。实例化这个类,然后设置构造器属性,sqlSessionFactory,引用上面的。executorType,的值为BATCH。

    6.mybatis-spring自动扫描包。<mybatis-spring:scan base-package="cn.taotao.dao">

    六、编写springmvc.xml文件,即springmvc的配置文件

    1.视图解析器,即InternalResourceViewResolver,实例化此bean,然后加入属性前缀和后缀。

    2. 自动扫描包,然后加入注解包含,只包含include   @Controller注解。同上面第五章节的第2步相反。在用这一步时,需要把默认的filter禁用。否则不起作用,use-default-filters="false"。另外像这样的操作,排除注解,一共有4个注解可以用,Component,Controller,Repository,Service。 在这个  package org.springframework.stereotype;在这个包上,open Type Hierarchy,即可查到。

    3. 自动注解驱动。

    4. 默认的serlvet处理器,用来处理静态资源。

    七、编写mybatis-config.xml文件。即Mybatis的配置文件,虽然大部分的配置已经移交给了applicationContext但是某些特殊的配置,仍然需要配置。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            <setting name="jdbcTypeForNull" value="NULL"/>
            
            <!--显式的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
            <setting name="cacheEnabled" value="true"/>
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="aggressiveLazyLoading" value="false"/>
        </settings>
    </configuration>

     八、编写mybatis的接口映射文件。即mapper。

    此文件的namespace属性,对应与实体接口类。id对应与接口的方法。此文件的存放位置默认与接口同一个目录,实践中可以放到资源目录下,建立与接口同级别的目录结构。编译器在打包时会自动导入一个包中。否则需要写mapper的地址映射位置。

    加入二级缓存ehcache,很简单,只要引入一个cache标签即可,然后提供一个xml的配置文件,后面有附录。前面pom坐标文件里,提供jar包的引用,他会自动把关联的ehcache的核心包引入。

    如果代码提示有问题,可以引入dtd文件约束,本系列的此文介绍  (推荐)eclpse maven 准备工作,补全自动生成目录文件夹,引入dtd约束。 cache类型的代码提示,可以在xml文件里按快捷键 Ctrl+shift+T打开。再或者在选中类,按Ctrl+T,打开。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="cn.taotao.dao.EmployeeMapper">  
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache> <select id="getEmpId" resultType="cn.taotao.bean.Employee"> select * from tbl_employee where id = #{id} </select> <select id="getEmps" resultType="cn.taotao.bean.Employee"> select * from tbl_employee </select> </mapper>

     这里需要提供一个ehcache的配置文件,放置到类路径下。

     echache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
     <!-- 磁盘保存路径 -->
     <diskStore path="D:44ehcache" />
     
     <defaultCache 
       maxElementsInMemory="10000" 
       maxElementsOnDisk="10000000"
       eternal="false" 
       overflowToDisk="true" 
       timeToIdleSeconds="120"
       timeToLiveSeconds="120" 
       diskExpiryThreadIntervalSeconds="120"
       memoryStoreEvictionPolicy="LRU">
     </defaultCache>
    </ehcache>
     
    <!-- 
    属性说明:
    l diskStore:指定数据在磁盘中的存储位置。
    l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
     
    以下属性是必须的:
    l maxElementsInMemory - 在内存中缓存的element的最大数目 
    l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
    l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
    l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
     
    以下属性是可选的:
    l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
    l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
     diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
    l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
    l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
    l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
     -->

    九、以下为代码片段

    dbconfig.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/test?allowMultiQueries=true
    jdbc.username=root
    jdbc.password=123456

    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:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
            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-4.3.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    
        <!-- 引入外部配置文件,实例化c3p0的数据源 -->
        <context:property-placeholder
            location="classpath:dbconfig.properties" />
        <bean id="dbSource"
            class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="jdbcUrl" value="${jdbc.url}"></property>
            <property name="driverClass" value="${jdbc.driver"></property>
            <property name="user" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
        
        <!-- 自动配置spring包扫描 -->
        <context:component-scan base-package="cn.taotao">
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
        
        <!-- 核心配置,配置mybatis的bean管理器 -->
        <bean id="sqlSessionFactoryBean"  class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="configLocation" value="classpath:mybatis-config.xml"></property>
            <property name="mapperLocations" value="classpath:/mapper/*"></property>
            <property name="dataSource" ref="dbSource"></property>
        </bean>
        
        <!-- 事务处理,驱动注解事务处理 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dbSource"></property>
        </bean>
        <tx:annotation-driven transaction-manager="transactionManager"/>
        
        <!-- 自动配置mybatis的包扫描,扫描接口包 -->
        <mybatis-spring:scan base-package="cn.taotao.dao"/>
        
        <!-- 配置一个可以批量处理的sqlsession,引用上面的mybatis实例化的bean -->
        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg>
            <constructor-arg name="executorType" value="BATCH"></constructor-arg>
        </bean>
    </beans>

    springmvc.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:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
            
            
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/pages/"></property>
                <property name="suffix" value=".jsp"></property>
            </bean>
            <context:component-scan base-package="cn.taotao" use-default-filters="false">    
                <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            </context:component-scan>
            <mvc:annotation-driven></mvc:annotation-driven>
            <mvc:default-servlet-handler/>
            
    </beans>

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>  
     <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
     version="2.5">  
       
       <!-- needed for ContextLoaderListener -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
    
        <!-- Bootstraps the root web application context before servlet initialization -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        
        <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
        <servlet>
            <servlet-name>springDispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!-- Map all requests to the DispatcherServlet for handling -->
        <servlet-mapping>
            <servlet-name>springDispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>

    bean代码

    package cn.taotao.bean;
    
    public class Employee {
    
        private int id;
        private String name;
        private String email;
        private String gender;
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getEmail() {
            return email;
        }
        public void setEmail(String email) {
            this.email = email;
        }
        public String getGender() {
            return gender;
        }
        public void setGender(String gender) {
            this.gender = gender;
        }
        @Override
        public String toString() {
            return "Employee [id=" + id + ", name=" + name + ", email=" + email + ", gender=" + gender + "]";
        }
        
    }

    dao 

    package cn.taotao.dao;
    
    import java.util.List;
    
    import cn.taotao.bean.Employee;
    
    public interface EmployeeMapper {
    
        public Employee getEmpById(int id);
        
        public List<Employee> getEmps();
    }

    service

    package cn.taotao.service;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.stereotype.Service;
    
    import cn.taotao.bean.Employee;
    import cn.taotao.dao.EmployeeMapper;
    
    @Service
    public class EmployeeService {
    
        @Autowired
        private EmployeeMapper empMapper;

         @Autowired
         private SqlSession sqlSession;

    public Employee getEmployeeById(int id) {
            return empMapper.getEmpById(id);
        }
        
        public List<Employee> getEmps(){
            
            return empMapper.getEmps();
        }
        
    }

    Controller,

    此代码中,@RequestMapping注解,用来相应某个href链接。传入的参数Map,会回传给页面,可以用EL表达式显示。返回的字符串list,是需要建立一个list.jsp文件。此返回值与jsp的文件名相同。

    在写这个类的时候,如果Map<String,Object>没有加变量名字,会出现上一行报错,或者提示没有}结尾。

    package cn.taotao.controller;
    
    import java.util.List;
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import cn.taotao.bean.Employee;
    import cn.taotao.service.EmployeeService;
    
    @Controller
    public class EmployeeController {
    
        @Autowired
        private EmployeeService empService;
        
        @RequestMapping("/getemps")
        public String getEmps(Map<String,Object> map) {
            List<Employee> emps = empService.getEmps();
            map.put("emps", emps);
            return "list";        
        }
        
    }

    jsp页面,需要引入servlet2.5以上。且引入c核心标签库。另外在开始的pom里,需要引入 jstl 和 taglib 的两个jar包库。

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
        <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    <h5>LIST Page</h5>
    <table>
    <tr>
    <td>id</td>
    <td>name</td>
    <td>email</td>
    <td>gender</td>
    </tr>
    <c:forEach items="${ emps}" var="e">
    <tr>
    <td>${e.id }</td>
    <td>${e.name }</td>
    <td>${e.email }</td>
    <td>${e.gender }</td>
    </tr>
    
    </c:forEach>
    
    </table>
    </body>
    </html>

    数据库

    SET FOREIGN_KEY_CHECKS=0;
    -- ----------------------------
    -- Table structure for tbl_employee
    -- ----------------------------
    CREATE TABLE `tbl_employee` (
      `id` int(11) NOT NULL auto_increment,
      `name` varchar(255) default NULL,
      `gender` char(1) default NULL,
      `email` varchar(255) default NULL,
      PRIMARY KEY  (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
    
    -- ----------------------------
    -- Records 
    -- ----------------------------
    INSERT INTO `tbl_employee` VALUES ('1', 'xuyong', 'F', '1213116@qq.com');
  • 相关阅读:
    嵌入式Linux学习笔记 NAND Flash控制器
    (嵌入式开发)自己写bootloader之编写第一阶段
    C_C++指针指针应用详解
    数据结构笔记-----二叉排序树和哈希表
    map方法和filter方法
    nginx服务器卡住了 解决办法
    vue-devtoools 调试工具安装
    web 本地存储(localStorage、sessionStorage)
    vux使用教程
    一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
  • 原文地址:https://www.cnblogs.com/sdgtxuyong/p/11799020.html
Copyright © 2020-2023  润新知