通過SSH搭建企業開發環境

一直沒有寫博客的習慣,但是這幾年走過來,卻發現了總沒留下什麼,所以是時候對過去做些記錄了,一是爲了緬懷過去,二是對技術重述,三是留作借鑑。

按照現在很多企業的開發都是基於springboot、或者一些微服務都用到了springcloud、dubbo,爲什麼會想着迴歸到以前的技術呢。我覺得,對於現在接觸軟件行業的人來說,對於工具的使用越來越容易了,但是對於技術的理解確越來越困難。由於太多的技術不斷髮展,而且發展的很快,不斷的改進、昇華、包裝,這些都是經驗與思想的結晶,對我們來說,只是看到了結果,確很難去看穿這些過程,那麼如何然我們去理解這些由於時代變遷與技術革新留下的成果物,是不是隻能從頭再來,這個真不得而知,每個人接觸新事物、學習能力、思維模式等等方面都有很大差異,沒有什麼方式能夠彌補時代欠下我們的經驗,那麼只有一步一個腳印,按自己的方式走下去了....

記得最開始進入這個行業,也是4年前了,那個時候用到的就是spring、springmvc、hibernate orm、jsp來完成企業項目的開發,那麼今天,我也將試着按照這樣的腳步走一遍。之後也會涉及到springboot、springcloud、mybatis、redis、zookeeper、vue等這些前後端目前都比較流行的技術進行下去,檔案更多的是完成效果,那麼具體爲什麼、如何理解等比較深層次的東西,只有在以後的日子慢慢理解,從源碼的角度與各種渠道進行解析,這是一個比較漫長的過程,包括現在,都是學習與記錄的過程。

現在同樣先構建一個maven的空項目,首先通過spring-bom配置spring環境依賴的各種jar的最佳版本,

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-framework-bom</artifactId>
                <version>3.2.16.RELEASE</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

然後無非就是spring的一些包,比如bean、core、context、web、mvc,檔案現在和hibernate配合,需要 shring的orm和hibernate-croe,當然還有一些數據庫驅動、數據庫連接池、json處理、測試、日誌以爲web開發相關的包,如servlet-api等。

一般mvc項目都會遵循這樣的結構:

3cf322f53ac5d1c183457a264eb34d4f122.jpg

其中core中主要會有一些擴展,這個可能只能在之後來慢慢補充了,由於這是一個簡單的應用,各個所有業務會劃分成多模塊存在與一個項目中,直接回存在一些依賴於調用。

可以看下實體是怎麼處理的:

@Data
@Entity
@Table(name = "USER")
@JsonIgnoreProperties({"password"})
public class User implements Domain {

    @Id
    @Column(name = "USER_ID",length = 36)
    @GeneratedValue(generator = "system-id")
    @GenericGenerator(name = "system-id", strategy = "uuid")
    private String userId;

    @JoinColumn(name = "AGENCY_ID")
    @ManyToOne(fetch = FetchType.LAZY)
    private Agency agency;

    @Column(name = "LOGIN_NAME",length = 56)
    private String loginName;

    @Column(name = "USER_CAPTION",length = 16)
    private String userCaption;

    @Column(name = "PASSWORD",length = 24)
    private String password;

    @Column(name = "BIRTHDAY",length = 24)
    private String birthday;

    @Column(name = "TELEPHONE",length = 16)
    private String telephone;

    @Column(name = "EMAIL",length = 36)
    private String email;

    @Column(name = "QQ",length = 12)
    private String qq;

    @Column(name = "WEIXIN",length = 56)
    private String weixin;

    @Column(name = "DESCRIPTION",columnDefinition="varchar(256)")
    private String description;
}

因爲使用的是hibernate orm,所以不會有hibernate的配置,這裏只用jpa的相關注解即可。同時由java 實體生成數據庫表,所以對每個屬性都加上了註解。而doa與service層則相對簡單

public interface UserDao extends Dao<User,String> {

}
@Repository
public class UserDaoImpl extends HibernateDao<User,String> implements UserDao {
    @Override
    protected Class<User> getModelClazz() {
        return User.class;
    }
}
public interface UserService extends BaseService {

    List<User> getUsers();

    User getUser(String id);

    User saveUser(User user);

    void removeUser(String id);
}
@Transactional
@Service
public class UserServiceImpl extends BaseServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    public List<User> getUsers() {
        return userDao.getAll();
    }

    @Override
    public User getUser(String id) {
        return userDao.get(id);
    }

    @Override
    public User saveUser(User user) {
        return userDao.save(user);
    }

    @Override
    public void removeUser(String id) {
        userDao.remove(id);
    }
}

其實可以看到,這些接口都有一定的普遍性,如果有多個功能模塊,基本都是一些重複複製的工作,所以完全可以在完成一定階段後,通過模板來生成這些代碼,網上有非常多的反向工程工具,同時通過一些模板框架如freemaker、volacity來實現,那麼只用保證代碼的統一結構後,就大大減少了工作量。

關於web層其實就是一些congtroller了,沒什麼特別的:

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @ResponseBody
    @RequestMapping("/getUsers")
    public List<User> getUsers(){
        return userService.getUsers();
    }

    @ResponseBody
    @RequestMapping("/getUser")
    public User getUser(@RequestParam String id){
        return userService.getUser(id);
    }

    @ResponseBody
    @RequestMapping("/saveUser")
    public User saveUser(User user){
        return userService.saveUser(user);
    }

    @ResponseBody
    @RequestMapping("removeUser")
    public void removeUser(@RequestParam String id){
        userService.removeUser(id);
    }
}

web資源都在webapp中,如下:

b38171cd772f376b24a67f0aacf9ca682d9.jpg

將css、js以及 靜態資源文件放在resources中,configs主要放各種擴展配置,pages就是頁面了。

首先可以看下web.xml的配置:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    metadata-complete = true,則servlet相關的註解
-->
<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_3_1.xsd"  version="3.1"  metadata-complete="true">

    <description>
        springmvc hibernate app
    </description>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/configs/spring/applicationContext.xml</param-value>
    </context-param>

    <!--  字符集過濾  -->
    <filter>
        <filter-name>encodingFilter</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>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--Open Session in View 解決lazy時加載問題-->
    <filter>
        <filter-name>openSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>singleSession</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>openSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>WEB-INF/configs/spring/applicationContext-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

這裏主要的配置就是spring的上下文已經web上下文。其次就是編碼過濾以及hibernate Open Session in View問題,關鍵監聽ContextLoaderListener,這個是springweb環境的重要處理環節。

最後要說的就是一些配置了,比如spring相關的,主要有兩個,一個是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"
       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 http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 掃描指定包下的spring註解,完成bean的註冊 -->
    <context:component-scan base-package="com.sucl.shms">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 加載屬性文件 -->
    <context:property-placeholder location="classpath*:configs/config-*.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!-- 初始化連接大小 -->
        <property name="initialSize" value="${jdbc.initialSize}"></property>
        <!-- 連接池最大數量 -->
        <property name="maxActive" value="${jdbc.maxActive}"></property>
        <!-- 連接池最大空閒 -->
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>
        <!-- 連接池最小空閒 -->
        <property name="minIdle" value="${jdbc.minIdle}"></property>
        <!-- 獲取連接最大等待時間 -->
        <property name="maxWait" value="${jdbc.maxWait}"></property>
        <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" />
        <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}" />
        <property name="validationQuery" value="${jdbc.validationQuery}" />
        <property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
        <property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
        <property name="testOnReturn" value="${jdbc.testOnReturn}" />
        <property name="maxOpenPreparedStatements" value="${jdbc.maxOpenPreparedStatements}" />
        <!-- 打開removeAbandoned功能 -->
        <property name="removeAbandoned" value="${jdbc.removeAbandoned}" />
        <!-- 1800秒,也就是30分鐘 -->
        <property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}" />
        <!-- 關閉abanded連接時輸出錯誤日誌 -->
        <property name="logAbandoned" value="${jdbc.logAbandoned}" />
    </bean>

    <!--配置session工廠-->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="com.sucl.shms.*.entity" />
        <property name="hibernateProperties">
            <props>
                <!--<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop> &lt;!&ndash; SessionFactory.getCurrentSession() 需要指定jta | thread | managed | custom &ndash;&gt;-->
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> <!--hibernate根據實體自動生成數據庫表-->
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>   <!--指定數據庫方言-->
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>     <!--在控制檯顯示執行的數據庫操作語句-->
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>     <!--在控制檯顯示執行的數據哭操作語句(格式)-->
            </props>
        </property>
    </bean>

    <!-- 事物管理器配置  -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
</beans>

這裏主要是添加包的掃描配置、屬性文件加載、數據源、orm依賴已經事務。

而web環境由於內容較少,配置也相對簡單:

<?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/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">

    <context:component-scan base-package="com.sucl.shms.*.web"/>

    <mvc:annotation-driven/>

    <mvc:default-servlet-handler/>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

其餘的無非就是一些頁面資源了,這個與我們所選擇的前端框架有關係,目前沒有做前後分離,但是從Controller可以看出,用了@ResponseBody,因此我們返回的已經是數據流,而非頁面了。

其實到這裏大的方面也差不多了,那麼還有一些點:

  • 數據庫操作的抽象
  • 代碼模板生成器的設計
  • 頁面與數據的控制
  • 異常處理
  • 前端界面的設計
  • 具體細節的說明
  • .....

還有很多都會在下一週全部完成。最後會形成一個比較完善可以直接使用的管理系統,當然只會包含系統模塊了。

代碼:https://github.com/suspring/springmvc-hibernate-ms 將會繼續更新。

處理代碼生成器沒有生成,其他功能都有個輪廓,前端採用layui實現,沒有做過多的包裝。

代碼生成器可以參考mybatis-plus的,代碼已經引入,需要從源碼分析如何從數據庫中取出相關的表、字段、類型等信息。

其餘功能目前不再完善,下一步將看看spring4.x通過註解方式構建web環境,。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章