1. 程式人生 > >SSH隨手記

SSH隨手記

cut ntp 引用 一對一 在線 容器 ESS 弱引用 tco

SSH是Spring + Struts + Hibernate,Struts是對Servlet的一個封裝,通過配置文件來達到對Web請求做處理;SpringMVC是對系統的設計,使用輕量級、最小侵入的原則,通過配置文件使得程序員可以更專註邏輯/業務處理;Hibernate是對jdbc的優化處理,可以使用Hibernate直接操作bean,使用hibernate中的Session來操作數據庫,支持事務處理。

Struts

一個基於MVC設計模式的Web應用框架,它本質上相當於一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。

主要配置struts.xml

<package name="default" namespace="" extends="struts-default">
  <action name="action" class="com.test.demo.Action" method="sayHello">
    <result name="success" value="">some.jsp</result>
  </action>
</package>

註解方式:

@ParentPackage("struts-default")// 與package中的extends功能一樣
@Namespace("/user")// package中的namespace一樣,指定上級請求 public class UserAction extends ActionSupport implements ServletRequestAware, ServletResponseAware { private static final long serialVersionUID = 1L; private HttpServletRequest req; private HttpServletResponse resp; @Action("/login")
public void login() throws Exception { // do login } }

上面的示例代碼中有實現 ServletRequestAwareServletResponseAware 接口,這兩個接口可以讓我們獲取到對應的 HttpServletRequest、HttpServletResponse

獲取其參數也可以通過Context:

ServletActionContext.getRequest();
ServletActionContext.getServletContext();
ServletActionContext.getContext().getParameters();

需要註意的是獲取post中的JSON數據時需要通過流的形式讀取,我這裏使用的是 BufferedReader 讀取其字符,並相應解碼:

    private String parseReq() throws IOException {
        BufferedReader br = this.request.getReader();
        String line = null;
        StringBuilder sb = new StringBuilder();
        while((line = br.readLine()) != null) {
            sb.append(line);
        }
        JSONObject json = JSON.parseObject(sb.toString());
        return json.toJSONString();
    }

Struts也可以實現輸入驗證及國際化,具體的請百度。可能listener這個配置我們開發中會用到,可以用來實現在線人數的統計,通過實現 HttpSessionListener 來監聽

// 會話被創建
default public void sessionCreated(HttpSessionEvent se) {}
// 會話被銷毀
default public void sessionDestroyed(HttpSessionEvent se) {}

如果需要實現其他的功能,可以設置其他的Listener,並獲取相應的數據,這裏就不說了。

Hibernate

1、配置文件:配置一些數據庫需要的基本數據,數據庫引擎、url、driver、用戶名、密碼等基本配置,還有就是hibernate的參數配置,能使性能更佳。

2、創建持久化對象

public class Bean {
  private int userId;
private String name; // ...... }

使用hibernate應該使用xml配置,獲取對應文件的獲取,文檔上介紹的是xml獲取效率更高

<hibernate-mapping>
    <class name="com.test.user.User" table="USER">
        <id name="userId" type="int">
            <column name="USERID" />
            <generator class="increment" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
    </class>
</hibernate-mapping>

3、獲取Configuration new StandardServiceRegistryBuilder().configure()

4、獲取SessionFactory

    private static void getSessionFactory() {
        final StandardServiceRegistry sr = new StandardServiceRegistryBuilder().configure().build();
        try {
            sf = new MetadataSources(sr).buildMetadata().buildSessionFactory();
        } catch (Exception e) {
            e.printStackTrace();
            StandardServiceRegistryBuilder.destroy(sr);
        }
    }

5、獲取Session接口操作數據庫

getSessionFactory();
s = sf.openSession();
session.set(s);

6、獲取事務接口Transaction

session.beginTransaction();
// some operations ;
transaction.commit()

7、通過 session.createQuery("HQL"); session.createSQLQuery("原生的sql語句"); 獲取Query實例

關於HQL語句

與原生SQL類似, from、select、where以及其他的運算符 ,HQL可以直接使用對象進行操作。Hibernate中的映射關系需要註意,

有一對一雙/單向、一對多單/雙、多對多單/雙向的配置問題,下面是一對一雙向的配置示例:

<!-- Person.hbm.xml -->
<
hibernate-mapping> <class name="Person" table="PERSON" lazy="true"> <id name="id" type="int"><column name="ID"/><generator class="native"/></id> <property name="name"/> <one-to-one name="idCard" class="IdCard" fetch="join" cascade="all"></one-to-one> </class> </hibernate-mapping>
<!-- IdCard.hbm.xml --> <hibernate-mapping> <calss name="IdCard" table="ID_CARD" lazy="true"> <id name="id" type="int"> <column name="ID"/> <!-- 引用person的主鍵作為IdCard的主鍵和外健 --> <generator class="foreign"> <param name="property">person</param> </generator> <id> <property name="cardNo"/> <!-- 表示IdCard引用了person的主鍵作為了外健 --> <one-to-one name="person" class="Person" constrained="true"></one-to-one> </class> </hibernate-mapping>

其相應的Java類

public class Person {
    private IdCard idCard;
    private String name;
    private int id;
    // get setter....
}

public class IdCard {
    private Person person;
    private String cardNo;
    private int id;
    // get setter....
}

Spring

IoC/DI

控制反轉/依賴註入,簡單來說就是由一個類(也就是Context)去創建bean對象,然後通過註入的方式產生使用類對bean的引用,bean的生命周期由Context控制。

示例:

class ADemo { public void methodA() { //...... } }
class BDemo { public void methodB() { //...... } }

如果在ADemo中需要使用到BDemo對象,那麽我們可以使用Context創建,就跟main函數一樣:

class ADemo {
    private BDemo b;
    public void setB(BDemo b) { this.b = b; }
    public void methodA() { b.methodB(); //...... }
}

class BDemo {
    public void methodB() { //...... }
}

class ExampleContext {
    public static void main(String[] args) {
        ADemo a = new ADemo();
        BDemo b = new BDemo();
        // 將b註入到使用者a中,這樣a只對b產生了引用,並沒有實際擁有
        // 一般想到的方法是向a中聲明一個屬性,然後通過set方法註入
        a.setB(b);
    }
}

當然也是可以使用構造器註入,接口註入(其實相當於方法註入)等等,最主要的思想是將a對b的一個強引用變成弱引用,使得使用者無需考慮其聲明周期及內存管理問題,同時還能將這個對象復用,減少多個重復對象的創建。

在Spring中通過 AnnotationConfigApplicationContext ClassPathXmlApplicationContext 讀取相關的配置,利用Java的反射機制獲取相關類並創建實例對象,在需要的時候註入到相關的類中。

AOP

AOP為Aspect Oriented Programming的縮寫,面向切面編程,在不改動原來代碼情況下插入需要執行的代碼,可以很好的處理日誌打印。簡單的理解就是在指定的規則下篩選出符合規定的方法,aop有before、after、around,可以在方法之前、之後、環繞的時候織入代碼。說到織入代碼,分為兩種:靜態織入、動態織入,靜態織入是需要借助 execution 表達式,表達式的格式為:

execution(<修飾符模式>?<返回類型模式><方法名模式>(<參數模式>)<異常模式>?)
// 比如:
@Before("execution(* com.demo.aop.BDemo.methodB(..))")
    public void methodA(JoinPoint jp) {
    // do something
}

動態織入我理解為做標記,由Spring容器發現需要織入的PointCut,首先需要定義一個註解,這個註解就是一個標記符,在告訴Spring 這是一個標記

// 只能方法使用
@Target(ElementType.METHOD)
// 運行時
@Retention(RetentionPolicy.RUNTIME)
public @interface ExampleAop {
    String name();
}

定義好了標記之後,就需要指定方法需要被關註,直接使用@ExampleAop("some info")來標記

@ExampleAop(name="註解式攔截的methodA")
public void methodA() {
    // do something
}

做完這些之後,我們需要對這個標記附上意義,就猶如你定義一個“?”操作符,如果你沒規定這個符號代表什麽,也就無法使用它,就像我們使用“+”表示兩個數的相加一樣,那麽我們將ExampleAop作為一個篩選的規則,所有打上這個標記的方法都需要執行某段代碼。如:

    // 註解式攔截
    @Pointcut("@annotation(com.demo.aop.ExampleAop)")
    public void annotionPointcut() {}    
    
    @Before("annotionPointcut()")
    public void methodBefore(JoinPoint jp) {
        System.out.println("上帝啊,竟然在一個切面裏添加多個Before,使用不同的方式攔截");
    }

所有由標記的方法都會在執行前加上一句打印。

在Spring MVC中,如果我們使這些打印實現的話,還需要配置文件,這裏我貼上代碼,就不詳細介紹了

@Configuration
@ComponentScan("com.demo.aop")
@EnableAspectJAutoProxy// 開啟對AspectJ代理的支持
public class ConfigAop {

}

需要了解更多的可以閱讀相關文檔(Spring家族文檔)

由於是接觸不久,很多地方無法詳細展開,希望能與大家一起探討。

寫在最後

以前覺得SSH項目太難搭建,在學習的過程中不斷的摸索,走過不少的彎路,很多的概念都是模糊的,現在想起來這些彎路給了我不少的經驗,至少讓我明白,知識是一點點攻破的,從Servlet到Struts,再到Spring MVC,兼顧JDBC、MySQL、Hibernate,了解了技術的不斷進步,編程思想的不斷成熟,看到不少大神們的不斷努力,也明白其實編程就是一種思想,不同的語言有著不同的規則/思想,只是為了更加的方便解決問題,組織起相應的功能。

SSH隨手記