第一章 自定義MVC框架
1.1 MVC模式設計
組成;Model:模型,用於數據和業務的處理
View :視圖,用於數據的顯示
Controller:控制器,用於進行流程控制
特色:1.一個模型能夠對應多個視圖
2.顯示與邏輯控制的分離
3.分層控制,減低了代碼間的耦合
1.2 DTD驗證XML文檔
聲明:<!DOCTYPE 根元素 [定義內容]>
例:<!DOCTYPE poem [
<!ELEMENT poem (author,title,content)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT content (#PCDATA)>
]>
<peom>
<author>王維</author>
<title>鹿柴</title>
<content>空山不見人,但聞人語聲。返景入深林,復照青苔上</content>
</peom>
使用外部DTD驗證XML
myStruts.dtd:
<!ELEMENT poems (poem*)>
<!ELEMENT poem (title,author,year,content)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT content (#PCDATA)>
myMvc.xml:
<!DOCTYPE poems SYSTEM "myStruts.dtd">
<poems>
<poem>
<title>春曉</title>
<author>孟浩然</author>
<content>春眠不覺曉......</content>
</poem>
</poems>
DTD元素
<!ELEMENT name CONTENT>
ELEMENT:關鍵字
name:元素名稱
CONTENT:元素類型
#PCDATA:任何字符數據,不能在其中包含任何子元素
純元素類型:只包含子元素,且這些子元素外沒有文本
符號:():表示分紅幾組
| :必須選其一
,:按順序出現
* :能夠出現0到屢次
?:可出現也可不出現,出現且只有一次
+ :必須出現,且能夠出現屢次
DTD屬性
<!ATTLIST 元素名稱 屬性名稱 屬性類型 屬性默認值>
屬性類型描述:
CDATA:字符數據
ID:惟一ID
IDREFS:另外一個ID
ENTITY:實體
ENTITIES:實體列表
屬性值描述:
#REQUIRED:屬性值是必須的
#IMPLIED:屬性值不是必須的
#FIXED:屬性值是固定的
例:<!DOCTYPE mystruts[
<!ELEMENT mystruts (actions)>
<!ELEMENT actions (action*)>
<!ELEMENT action (result*)>
<!ATTLIST auction
name CDATA #REQUIRED
CLASS CDATA #REQUIRED>
<!ATTLIST result
name CDATA #IMPLIED
redirect (true|false) "false">
]>
<mystruts>
<actions>
<action name="register" class="cn.jbit.action.RegisterAction">
<result name="success">page/login.jsp</result>
<result name="input">page/register.jsp</result>
</action>
<action name="login" class="cn.jbit.mvc.LoginAction">
<result name="success">page/guanli.jsp</result>
<result name="input">page/login.jsp</result>
</action>
</actions>
</mystruts>
1.3 XML文檔解析
獲取root節點 ELement root
一、獲取節點名稱 root.getName()
二、獲取節點屬性 root.attribute("dname")
三、獲取節點中的text root.getText()
四、獲取子節點
使用DOM4J操做XML數據(如:dom4j-1.6.1.jar)
例:student.xml:
<?xml version="1.0" encoding="gb2312"?>
<students>
<student age="31"><!-- 若是沒有固定的age 默認爲20 -->
<name>崔衛兵</name>
<college>pc學院</college>
<telephone>6234666</telephone>
<notes>男,1985年出生,碩士</notes>
</student>
<student>
<name>張洪澤</name>
<!-- 若是沒有固定的leader 默認爲leader -->
<college leader="Leader">pc學院</college>
<telephone>6238888</telephone>
<notes>男,1987年出生,碩士</notes>
</student>
</students>
Dom4jReadExmple.java:
public class Dom4jReadExmple {
public void iterateWholeXML(String filename,HashMap<String,String> hm){
SAXReader saxReader=new SAXReader();
try {
Document document=saxReader.read(new File(filename));
Element root=document.getRootElement();
int num=-1;//記錄學生編號的變量
//遍歷根元素(students)的全部子節點(student)
for(Iterator iter=root.elementIterator();iter.hasNext();){
Element element=(Element) iter.next();
num++;
//獲取person節點的age屬性
Attribute ageAttribute=element.attribute("age");
if(ageAttribute!=null){
String age=ageAttribute.getValue();
if(age!=null && !age.equals("")){
hm.put(element.getName()+"-"+ageAttribute.getName()+num, age);
}else{
hm.put(element.getName()+"-"+ageAttribute.getName()+num, "20");
}
}else{
hm.put(element.getName()+"-age"+num, "20");
}
//遍歷student節點下的全部子節點(name,college,telephone,notes)
for(Iterator iterInner=element.elementIterator();iterInner.hasNext();){
Element elementInner=(Element) iterInner.next();
if(elementInner.getName().equals("college")){
hm.put(elementInner.getName()+num,elementInner.getText());
//獲取college節點的leader屬性
Attribute leaderAttr=elementInner.attribute("leader");
if(leaderAttr!=null){
String leader=leaderAttr.getValue();
if(leader!=null && !leader.equals("")){
hm.put(elementInner.getName()+"-"+leaderAttr.getName()+num,leader);
}else{
hm.put(elementInner.getName()+"-"+leaderAttr.getName()+num,"leader");
}
}else{
hm.put(elementInner.getName()+"-leader"+num, "leader");
}
}else{
hm.put(elementInner.getName()+num, elementInner.getText());
}
}
}
} catch (DocumentException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
TestDom4jReadExmple.java:
public class TestDom4jReadExmple {
public static void main(String[] args) {
try {
//獲取解析後的解析信息
HashMap<String, String> hashMap;
Dom4jReadExmple dre=new Dom4jReadExmple();
//遍歷xml文件
hashMap=new HashMap<String, String>();
String n=System.getProperty("user.dir");
//獲取xml文件
dre.iterateWholeXML(n+"\\src\\cn\\jbit\\action\\Student.xml", hashMap);
for (int i = 0; i < hashMap.size(); i++) {
int j=i/6;
System.out.print(hashMap.get("name"+j)+"\t");
System.out.print(hashMap.get("student-age"+j)+"\t");
System.out.print(hashMap.get("college"+j)+"\t");
System.out.print(hashMap.get("college-leader"+j)+"\t");
System.out.print(hashMap.get("telephone"+j)+"\t");
System.out.println(hashMap.get("notes"+j)+"\t");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
輸出結果:崔衛兵 31 pc學院 leader 6234666 男,1985年出生,碩士
張洪澤 20 pc學院 Leader 6238888 男,1987年出生,碩士
關鍵操做以下:
一、Document對象相關
SAXReader saxReader=new SAXReader();
Document document=saxReader.read(new File("index.xml"));
二、節點相關
一、獲取文檔的根節點
Element root=document.getRootElement();
二、獲取某節點的單個子節點
Element meberElm=root.element("Member");
三、取得節點的文字
String text=MemberElm.getText();
四、取得某節點下名爲:Member的全部子節點並進行遍歷
List nodes=rootElm.elements("Member");
五、對某節點下的全部子節點進行遍歷
for(Iterator iterInner=element.elementIterator();iterInner.hasNext();){
Element elementInner=(Element) iterInner.next();
//...
}
六、在某節點下添加子節點
Element ageElm=newMemberElm.addElement("age");
七、設置節點文字
ageElm.setText("19");
八、刪除某節點
parentElm.remove(childElm);//childElm是待刪除的節點,parentElm是父節點
九、添加一個CDATA節點
Element contentElm=infoElm.addElement(content);
contentElm.addCDATA(diary.getContent());
contentElm.getText();
contentElm.clearContent();
三、屬性相關
一、取得某節點下的屬性
Element root=document.getRootElement();
Attribute ageAttribute=root.attribute("age");
二、取得屬性的文字
String text=ageAttribute.getText();
三、遍歷某節點的全部屬性
Element root=document.getRootElement();
for(Iterator it=root.elementIterator();it.hasNext();){
Attribute attribute=(Attrinute) it.next();
String text=ageAttribute.getText();
System.out.print(text);
}
四、設置某節點的屬性和文字
newMemberElm.addAttribute("name","sitinspring');
五、設置屬性的文字
Attribute attribute=root.attribute("age");
attribute.setText("sitinspring");
1.4 反射機制
反射的3個動態性質
1.運行時伸出對象實例
2.運行期間調用對象
3.運行時更改對象
反射經常使用API
Class類:反射核心類
Field類:類的屬性
Method類:類的方法
Constructor類:類的構造方法
使用反射的步驟
一、導入jar包
二、得到須要操做的類的java.lang.CLass對象
三、調用Class的方法獲取Field、Method等對象
四、使用反射API進行操做
反射的應用
一、獲取Class對象
例;
Class clazz=Class.forName("java.lang.String");//正確
Class clazz=Class.forName("String");//錯誤
二、從Class對象獲取信息
訪問類信息的經常使用方法
Constructor[] getConstructors()//返回所表示的類的public構造方法
Constructor[] getDeclaredConstructors()//返回所表示的類的構造方法
Method [] getMethods()//返回所表示的類的public方法
Method [] getDeclaredMethods()//返回所表示的類的所有方法
Field[] getFields()//返回所表示的類的public屬性
field[] getDeclaredFields()//返回所表示的類的所有屬性
Object get(Object obj)//獲得引用類屬性值
void set(Object obj,Object val)//將Obj對象的屬性設置val值,針對引用類型
Object invoke(Object obj,Object args)//調用類的方法obj是執行方法的對象,args是執行方法時傳入的參數
三、建立對象
newInstance():
例:Object retBean=defaultCtor.newInstance();
1.5 構建基於MVC模式的框架(Controller爲MVC的核心)
1.5.一、Controller的設計
一、定義Action接口
public interface Action {
public String execute(HttpServletRequest request,HttpServletResponse response)throws Exception;
}
實現接口:
public class LoginAction implements Action {
@Override
public String execute(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String name=request.getParameter("name");
String password=request.getParameter("password");
//業務處理
UserBiz userBiz=new UserBizImpl();
User user=userBiz.login(name,password);
//判斷是否登陸成功
if(user==null){
request.setAttribute("message","用戶名或密碼錯誤!");
return "/page/login.jsp";
}else{
request.getSession().setAttribute("login", user);
return "/page/guanli.jsp";
}
return null;
}
}
二、實現Controller類
public class ActionFilter implements Filter {
private FilterConfig config;
private ActionMappingManager mappingManager;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//將請求裝換成HttpServletRequest
HttpServletRequest hsr=(HttpServletRequest) request;
HttpServletResponse hsp=(HttpServletResponse) response;
//調用Action的execute方法
Action action=this.getAction(hsr);
String resultView=null;
try {
resultView=action.execute(hsr, hsp);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
//頁面跳轉
if(resultView!=null){
request.getRequestDispatcher(resultView).forward(request, response);
}
}
@Override
public void init(FilterConfig conf) throws ServletException {
this.config=conf;
String conStr=config.getInitParameter("config");
//可包含多個配置文件
String[] configFiles=null;
if(conStr==null||conStr.isEmpty()){
configFiles=new String[]{"myMvc.xml"};
}else{
//拆分配置文件名稱字符串
configFiles=conStr.split(",");
}
this.mappingManager=new ActionMappingManager(configFiles);
}
private Action getAction(HttpServletRequest request) {
//獲取請求的uri
String uri = request.getRequestURI();
//獲取上下文路徑
String contextPath=request.getContextPath();
//截取上下文路勁後面的部分
String actionPath=uri.substring(contextPath.length());
//獲取Action名稱
String actionName=actionPath.substring(1,actionPath.lastIndexOf(".")).trim();
Action action=null;
//添加新功能時在這裏添加
if("login".equals(actionName)){
action=new LoginAction();
}
return null;
}
}
web.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
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_3_0.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>requestFilter</filter-name>
<filter-class>cn.jbit.mvc.ActionFIlter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
</web-app>
1.6 升級Controller控制器
一、配置文件
myStruts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mystruts[
<!ELEMENT mystruts (actions)>
<!ELEMENT actions (action*)>
<!ELEMENT action (result*)>
<!ATTLIST auction
name CDATA #REQUIRED
CLASS CDATA #REQUIRED>
<!ATTLIST result
name CDATA #IMPLIED
redirect (true|false) "false">
]>
<mystruts>
<actions>
<action name="register" class="cn.jbit.action.RegisterAction">
<result name="success">page/login.jsp</result>
<result name="input">page/register.jsp</result>
</action>
<action name="login" class="cn.jbit.mvc.LoginAction">
<result name="success">page/guanli.jsp</result>
<result name="input">page/login.jsp</result>
</action>
</actions>
</mystruts>
二、保存Action信息
public class ActionMapping {
//action元素的name屬性
private String name;
//action元素的className屬性
private String className;
//保存配置愛的result屬性信息
private Map<String, String > resultMap=new HashMap<String, String>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Map<String, String> getResultMap() {
return resultMap;
}
public void setResultMap(Map<String, String> resultMap) {
this.resultMap = resultMap;
}
/*
* 根據result-name返回Result實例
*/
public String getResult(String name,String result){
return resultMap.get(name);
}
public String getResult(String name){
return resultMap.get(name);
}
/*
* 向Map中添加一個View
*/
public void addResult(String name,String result){
this.resultMap.put(name, result);
}
}
三、讀取配置文件
public class ActionMappingManager {
//保存全部Action的ActionMapping
private static Map<String,ActionMapping> actionMappings=new HashMap<String, ActionMapping>();
/**
* init方法用來加載Action配置文件
* @param configureFileName 配置文件名
*/
public void init(String configureFileName){
try {
if(configureFileName==null || configureFileName.isEmpty()){
throw new Exception("ConfigureFileName爲空");
}
InputStream is=this.getClass().getResourceAsStream("/"+configureFileName);
Document doc=new SAXReader().read(is);
Element root=doc.getRootElement();
Iterator<Element> actionsIt=root.elements("actions").iterator();
Element actions =actionsIt.next();
for(Iterator<Element> actionIt=actions.elementIterator("action");actionIt.hasNext();){
Element action=actionIt.next();
ActionMapping mapping=new ActionMapping();
mapping.setName(action.attributeValue("name"));
mapping.setClassName(action.attributeValue("class"));
for(Iterator<Element> resultIt=action.elementIterator("result");resultIt.hasNext();){
Element resultElement=resultIt.next();
String name=resultElement.attributeValue("name");
String result=resultElement.getText();
if(name==null || "".equals(name)){
name="success";
}
mapping.addResult(name, result);
}
actionMappings.put(mapping.getName(), mapping);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* 加載Action配置文件
* @param configureFileNames 配置文件名的數組
*/
public ActionMappingManager(String[] configureFileNames){
for(String configureFileName:configureFileNames){
init(configureFileName);
}
}
/**
* 根據actionName查詢對應的ActionMapping實例
* @param actionName
* @return
* @throws Exception
*/
public ActionMapping getActionMappingByName(String actionName)throws Exception{
if(actionName==null || actionName.isEmpty()){
return null;
}
ActionMapping mapping=this.actionMappings.get(actionName);
if(mapping==null){
throw new Exception("mapping爲空:["+actionName+"]");
}
return mapping;
}
}
四、反射生成Action
public class ActionManager {
public static Action createAction(String className)throws Exception{
try {
return (Action)loadClass(className).newInstance();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (InstantiationException e) {
e.printStackTrace();
}catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
private static Class loadClass(String className) throws ClassNotFoundException {
Class clazz=null;
clazz=Class.forName(className);
return clazz;
}
}
五、完善Controller
web.xml:
<filter>
<display-name>requestFilter</display-name>
<filter-name>requestFilter</filter-name>
<filter-class>cn.jbit.mvc.ActionFIlter</filter-class>
<init-param>
<param-name>config</param-name>
<param-value>myMvc.xml</param-value>
</init-param>
</filter>
ActionFilter.java修改:
public class ActionFilter implements Filter {
private FilterConfig config;
private ActionMappingManager mappingManager;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//將請求裝換成HttpServletRequest
HttpServletRequest hsr=(HttpServletRequest) request;
HttpServletResponse hsp=(HttpServletResponse) response;
try {
ActionMapping mapping=this.getActionMapping(hsr);
Action action=ActionManager.createAction(mapping.getName());
//獲得結果的邏輯名
String resultName=action.execute(hsr, hsp);
//根據邏輯名返回實際跳轉的視圖名,也就是跳轉的路徑
String result=mapping.getResult(resultName);
if(result==null){
return;
}
//頁面跳轉
hsp.sendRedirect(result);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
@Override
public void init(FilterConfig conf) throws ServletException {
this.config=conf;
String conStr=config.getInitParameter("config");
//可包含多個配置文件
String[] configFiles=null;
if(conStr==null||conStr.isEmpty()){
configFiles=new String[]{"myMvc.xml"};
}else{
//拆分配置文件名稱字符串
configFiles=conStr.split(",");
}
this.mappingManager=new ActionMappingManager(configFiles);
}
private ActionMapping getActionMapping(HttpServletRequest request) throws Exception {
//獲取請求路徑
String uri=((HttpServletRequest)request).getRequestURI();
String contextPath=((HttpServletRequest)request).getContextPath();
//截取上下文路勁後面的部分
String actionPath=uri.substring(contextPath.length());
//獲取Action名稱
String actionName=actionPath.substring(1,actionPath.lastIndexOf(".")).trim();
ActionMapping mapping=null;
mapping=mappingManager.getActionMappingByName(actionName);
return mapping;
}
}java