JAVAEE框架學習——Struts2——Action API 使用

weixin_34124651發表於2018-05-30

Action API

通過ActionContext 獲取不同域物件 存放值

  • Object get(Object key) 類似於呼叫HttpServletRequest 的 getAttribute(String name)方法
  • Map getApplication() 返回一個Map物件 該物件模擬了應用ServletContext例項
  • static ActionContext getContext() 靜態方法 獲取系統的ActionContext例項
  • Map getParameters() 獲取所有的請求引數。類似呼叫HttpServletRequest物件的getParameterMap()方法
  • Map getSession() 返回一個Map物件 該Map物件模擬了HttpSession例項
  • void setApplication(Map application) 直接傳入一個Map例項,將該Map例項裡的key-value物件轉換成application的屬性名、屬性值
  • void setSession(Map session) 直接傳入一個Map例項,將該Map例項裡的key-value對轉換成session的屬性名、屬性值

結果跳轉方式

Struts2中常用的結果跳轉方式有4中:

轉發

 <package name="result" extends="struts-default">
        <action name="Demo1Action" class="cn.probuing.struts2lesson.action.Demo1Action">
            <result name="success" type="dispatcher">/hello.jsp</result>
        </action>
</package>

檢視原始碼分析

Struts2按照struts-default.xml配置檔案可以找到 dispathcer對應的類 名為
rg.apache.struts2.dispatcher.ServletDispatcherResult
進入這個類中,我們可以看到如下的程式碼

 /**
     * Dispatches to the given location. Does its forward via a RequestDispatcher. If the
     * dispatch fails a 404 error will be sent back in the http response.
     *
     * @param finalLocation the location to dispatch to.
     * @param invocation    the execution state of the action
     * @throws Exception if an error occurs. If the dispatch fails the error will go back via the
     *                   HTTP request.
     */
    public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Forwarding to location " + finalLocation);
        }

        PageContext pageContext = ServletActionContext.getPageContext();

        if (pageContext != null) {
            pageContext.include(finalLocation);
        } else {
            HttpServletRequest request = ServletActionContext.getRequest();
            HttpServletResponse response = ServletActionContext.getResponse();
            RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);

            //add parameters passed on the location to #parameters
            // see WW-2120
            if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf("?") > 0) {
                String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);
                Map<String, Object> parameters = getParameters(invocation);
                Map<String, Object> queryParams = urlHelper.parseQueryString(queryString, true);
                if (queryParams != null && !queryParams.isEmpty())
                    parameters.putAll(queryParams);
            }

            // if the view doesn't exist, let's do a 404
            if (dispatcher == null) {
                response.sendError(404, "result '" + finalLocation + "' not found");
                return;
            }

            //if we are inside an action tag, we always need to do an include
            Boolean insideActionTag = (Boolean) ObjectUtils.defaultIfNull(request.getAttribute(StrutsStatics.STRUTS_ACTION_TAG_INVOCATION), Boolean.FALSE);

            // If we're included, then include the view
            // Otherwise do forward
            // This allow the page to, for example, set content type
            if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {
                request.setAttribute("struts.view_uri", finalLocation);
                request.setAttribute("struts.request_uri", request.getRequestURI());

                dispatcher.forward(request, response);
            } else {
                dispatcher.include(request, response);
            }
        }
    }

由原始碼可以看到

  • 先通過ServletActionContext.getRequest() 獲取到了HttpServletRequest 這就是請求物件
  • 通過ServletActionContext.getResponse()獲取到了HttpServletResponse() 響應物件
  • 通過請求和響應物件來進行結果的操作,其中
    * 請求物件 request.getRequestDispatcher() 獲得轉發器,在最後dispathcer.forward(req,res)
    可以看出 Struts2的轉發 就是封裝的Servlet的轉發,加入了一些邏輯

重定向

<package name="result" extends="struts-default">
     <action name="Demo2Action" class="cn.probuing.struts2lesson.action.Demo2Action">
            <result name="success" type="redirect">/hello.jsp</result>
        </action>
    </package>

檢視原始碼分析

HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);
sendRedirect(response, finalLocation);

同樣 封裝的Servlet重定向

轉發到Action

   <action name="Demo3Action" class="cn.probuing.struts2lesson.action.Demo3Action">
            <result name="success" type="chain">
                <!--結果集完成後會轉發到namespace上的actionName-->
                <param name="actionName">Demo1Action</param>
                <param name="namespace">/</param>
            </result>
        </action>

重定向到Action

 <action name="Demo4Action" class="cn.probuing.struts2lesson.action.Demo4Action">
            <result name="success" type="redirectAction">
                <param name="actionName">Demo1Action</param>
                <param name="namespace">/</param>
            </result>
        </action>

獲得Servlet API

Struts2的Action沒有與任何Servlet API耦合,這是Struts2的一個改良之處

原理

6052465-7e6fade713d83955.png
原理

通過ActionContext

Struts2提供了ActionContext來訪問Servlet API ActionContext是Action執行的上下文物件。在ActionContext中儲存了Action執行所需要的所有物件。包括parameters,request,session,application等

 ActionContext context = ActionContext.getContext();
        //獲得request域 struts不推薦使用request域
        Map<String, Object> requestScope = (Map<String, Object>) context.get("request");
        //推薦 ActionContext
        ActionContext.getContext().put("name", "requestTom");

        //獲得session域
        Map<String, Object> session = context.getSession();
        session.put("name", "sessionTom");
        //獲得application域
        Map<String, Object> application = context.getApplication();
        application.put("name", "applicationTom");
        return SUCCESS;

獲得session域

  • Map<String, Object> session = context.getSession();

獲得Application域

  • Map<String, Object> application = context.getApplication();

通過ServletActionContext

為了直接訪問Servlet API Struts2框架還提供了ServletActionContext類

public String execute(){
        //原生request
        HttpServletRequest request = ServletActionContext.getRequest();
        //原生session
        HttpSession session = request.getSession();
        //原生response
        HttpServletResponse response = ServletActionContext.getResponse();
        //原生servletContext
        ServletContext servletContext = ServletActionContext.getServletContext();
        return SUCCESS;
    }

通過實現介面方式

6052465-065f46629b946a89.png
Struts2介面
public class Demo7Action extends ActionSupport implements ServletRequestAware, ServletResponseAware, ServletContextAware {
    private ServletContext context;
    private HttpServletRequest request;
    private HttpServletResponse resp;

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.resp = response;
    }

    @Override
    public void setServletContext(ServletContext context) {
        this.context = context;
    }

    public String execute() throws Exception {
        System.out.println("原生request" + request);
        return SUCCESS;
    }

由攔截器完成

Action中獲得引數

第一種:通過與引數鍵名稱相同的屬性

 private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(this.name);
        return SUCCESS;
    }

屬性驅動獲得引數

 private String name;
    private Integer age;
    private Date birthday;

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(this.name);
        System.out.println(this.age);
        System.out.println(this.birthday);
        return SUCCESS;
    }
<form action="${pageContext.request.contextPath}/Demo8Action" method="post">
    使用者名稱:<input type="text" name="name"/><br/>
    年齡:<input type="text" name="age"/><br/>
    生日:<input type="text" name="birthday"/><br/>
    <input type="submit" value="提交"/>
</form>

第二種 物件驅動

  • 建立物件
public class User {
    private String name;
    private Integer age;
    private Date birthday;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}
  • 頁面指定提交到物件的對應屬性
<form action="${pageContext.request.contextPath}/Demo9Action" method="post">
    使用者名稱:<input type="text" name="user.name"/><br/>
    年齡:<input type="text" name="user.age"/><br/>
    生日:<input type="text" name="user.birthday"/><br/>
    <input type="submit" value="提交"/>
</form>
  • Action 中聲名物件屬性
  private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String execute() throws Exception {
        System.out.printf(this.user.toString());
        return SUCCESS;
    }

其實某種意義上 物件驅動和屬性驅動沒有什麼區別,只是將屬性換成了物件

第三種 模型驅動

  • Action實現ModelDriven<模型>介面
public class Demo10Action extends ActionSupport implements ModelDriven<User> {

    private User user = new User();


    @Override
    public String execute() throws Exception {
        System.out.printf(this.user.toString());
        return SUCCESS;
    }

    /**
     * @return 返回需要封裝的物件
     */
    @Override
    public User getModel() {
        return user;
    }
}
  • 頁面正常提交
<form action="${pageContext.request.contextPath}/Demo10Action" method="post">
    使用者名稱:<input type="text" name="name"/><br/>
    年齡:<input type="text" name="age"/><br/>
    生日:<input type="text" name="birthday"/><br/>
    <input type="submit" value="提交"/>
</form>

缺點:封裝的模型單一

原理(正在學習 日後補)

集合型別引數封裝

封裝list

  • Action類
 private List<String> list;

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    @Override
    public String execute() throws Exception {
        System.out.println("list" + list);
        return SUCCESS;
    }
  • 頁面page
    list:<input type="text" name="list"/>
    list:<input type="text" name="list[1]"/>
    <input type="submit" value="提交"/>

前端表單指定name="list" Struts2直接將引數封裝到list集合中

指定新增索引

   list:<input type="text" name="list[1]"/>

封裝Map

  • Action類
 public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public List<String> getList() {
        return list;
    }
@Override
    public String execute() throws Exception {
        System.out.println("list" + list);
        System.out.println("map" + map);
        return SUCCESS;
    }
  • 頁面page
    list:<input type="text" name="map['haha']"/>

擴充套件知識

StrutsMVC

6052465-1e06f58e71265a27.png
StrutsMVC

Action 生命週期

  • 每次接收請求到來時,都會建立一個新的Action例項
  • Action是執行緒安全的,可以使用成員變數接收引數

相關文章