SSH隨手記
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 } }
上面的示例代碼中有實現 ServletRequestAware 和 ServletResponseAware 接口,這兩個接口可以讓我們獲取到對應的 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隨手記