Struts2 preliminary use

struts is a web application framework based on the MVC design pattern in Java. A new framework developed on the basis of absorbing struts1 and webwork. Its working principle is shown in the following figure:

  1. After the HTTP request arrives, it first passes the ActionContextCleanUp filter to eliminate the attribute, so as to extend the life cycle of the attribute in the Action. After passing through other filters such as SiteMesh, the request is passed to the StrutsPrepareAndExecuteFilter core control filter
  2. StrutsPrepareAndExecuteFilter determines which Action to call through the ActionMapper mapper, and then transfers control to the ActionProxy proxy
  3. ActionProxy calls the configuration manager ConfigurationManager to read configuration information from the configuration file struts.xml and create ActionInvocation objects
  4. ActionInvocation goes through the interceptor chain in turn and then calls Action, according to the result string returned by the Action to find the corresponding Result
  5. Result calls the view template, then executes the interceptor chain in the reverse order, and returns the HttpServlet response
  6. The HTTP response passes through Struts and user-defined filters in the reverse order, and returns the result to the client.

Create a struts project

After creating a new Java web project, first import the required jar packages, download the required dependency packages from the struts official website https://struts.apache.org/download.cgi , select the latest version 2.5.22 All dependencies package, and unzip it For multiple jar packages, select the following necessary copies from them to the project lib folder and add them to the dependencies. The directory structure of the project is as follows

Then configure struts2 filter StrutsPrepareAndExecuteFilter in the web.xml file to filter all paths

<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Then define the Action class, create a new action.FirstAction in the src directory, inherited from the ActionSupport class,

package action;

import com.opensymphony.xwork2.ActionSupport;

public class FirstAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        System.out.println("Action执行");
        return SUCCESS;                        //返回字符串SUCCESS
    }
}

Create a struts.xml file in the src directory, which is the core configuration file of struts2, complete the configuration of the action, and the corresponding result definition and other functions.

<package> is a package. A package can contain multiple actions. The name attribute is the package name, the extends attribute is the inherited package name, and the namespace is the namespace. The namespace needs to be added when accessing the action through the url level. download, when accessing, the url is http: // localhost: 8080: projectname / download / xxx, if "/" represents the root namespace, it can be omitted.

The name attribute of <action> is the URL path to be accessed, for example, here is / firstaction, and class is the corresponding Java class.

<result> Defines the returned result set page, and returns different interfaces according to different name attributes. The name attribute defaults to SUCCESS, so here the default return interface success.jsp

The <constant> tag can define constants in the form of key-value pairs, where name is the key and value is the value

In addition, you can use the <include> tag to import other struts xml configuration files

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
    <package name="default" namespace="/" extends="struts-default">
        <action name="firstaction" class="action.FirstAction">
            <result>/success.jsp</result>
        </action>
    </package>
    <constant name="struts.url.http.port" value="8080"></constant>
</struts>

Start the project to access firstaction, output "Action execution" in the console and jump to the success.jsp page, such a basic struts project will run.

Action

Access Servlet API

Http request comes to action through the filter, and returns the result after performing the operation, so how to get the Request and Response objects? Struts provides three methods

The first is to obtain the request, response, and context objects in the setXxx () method of the interface by implementing the corresponding Aware interface . Then set and get the properties through their corresponding methods. This method is severely coupled with the Servlet API and is not recommended

public class FirstAction extends ActionSupport
        implements ServletRequestAware, ServletResponseAware, ServletContextAware {        //实现相应接口
    HttpServletRequest request;
    HttpServletResponse response;
    ServletContext application;

    @Override
    public void setServletRequest(HttpServletRequest httpServletRequest) {
        this.request=httpServletRequest;        //获取request对象
    }

    @Override
    public void setServletResponse(HttpServletResponse httpServletResponse) {
        this.response=httpServletResponse;      //获取response对象
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.application=servletContext;        //获取application对象
    }

    @Override
    public String execute() throws Exception {
        request.setAttribute("key1","value1");                //设置属性
        System.out.println(request.getAttribute("key1"));     //获取属性
        return SUCCESS;
    }
}

The second method is to get the real Servlet-related APIs through the static method getXxx () in the ServletActionContext class. After that, set and get attributes with the setAttribute and getAttribute methods of the request, session, and application objects

HttpServletRequest request= ServletActionContext.getRequest();  //获取request对象
HttpSession session=request.getSession();                       //获取session对象
ServletContext context=ServletActionContext.getServletContext();//获取全局application对象
session.setAttribute("key3","value3");                          //设置属性值
System.out.println(session.getAttribute("key3"));               //获取属性值

The third is to access the Servlet API through the ActionContext class. Struts2 encapsulates the Servlet object again using the Map collection. You can directly manipulate the shared data in the application, session and request objects through the Map collection. a method. Through the ActionContext object, you can directly call the get / put method to get and set the object saved in the request. Through getApplication (), getSession (), getParameters () can get the application object, session object and parameter parameters in the request request. Since this method does not obtain a real Servlet API object, the returned data is of the Map type, so the data can be set and obtained through the Map's put / get method.

        ActionContext actionContext=ActionContext.getContext();     //创建Context对象

        actionContext.put("key1","value1");                 //向request中存储对象
        System.out.println(actionContext.get("key1"));      //获取request中存储的信息

        Map application=actionContext.getApplication();     //获取application
        application.put("key2","value2");                   //向application对象存对象
        System.out.println(application.get("key2"));        //从application中取出对象

Access action url order

Since the package of struts can be nested, the URL path to be accessed can also have multiple layers. For example, a package1 has a subpackage subpackage that contains firstaction, and its access path is http: // localhost: 8080 / Struts2Demo / package1 / subpackage / firstaction . If the firstaction is not found in the subpackage, it will return to the upper level package1 to find, if it still has not returned to the root directory of the upper level to find, if it is not found, it will report an error 404.

Calling action method dynamically

If you want to call different methods in the same action for different URLs, you need to call them dynamically. The first one can specify which method in the action class to call through the method attribute in the <action> tag. As shown below, when the access URL is loginaction, struts will execute the login () method in action.FirstAction and jump to the login.jsp page after returning to SUCCESS

        <action name="loginaction" class="action.FirstAction" method="login">
            <result>/login.jsp</result>
        </action>

However, if you need to define an action for each url, it is too repetitive and troublesome. You can use wildcards to define different calling methods according to different urls. For example, define the name of the action as "hello_ *", use * to represent wildcards and separate them from other urls, and use {1} in the method to represent the first position of wildcards. When the url we visit is hello_login, {1} represents login, corresponding to the implementation of the login method in FirstAction, login () returns the string as login, find the label whose name is login in <result>, and return /login.jsp page. When accessing hello_logout, logout () is executed and /logout.jsp is returned. It can be seen that the functions of dynamically calling action and dynamically returning to the page are realized according to different incoming urls.

    <package name="default" namespace="/" extends="struts-default">
        <global-allowed-methods>regex:.*</global-allowed-methods>
        <action name="hello_*" method="{1}" class="action.FirstAction">
            <result name="{1}">/{1}.jsp</result>
        </action>
    </package>
public class FirstAction extends ActionSupport{
    public String login(){
        return "login";
    }

    public String logout(){
        return "logout";
    }
}

Default Action

You can specify the default access path in the package through the default-action-ref tag, that is, other requests in addition to the defined normal path will jump to the action. For example, define the default action as error, and define the action as error to jump to the error.jsp page

<package name="default" namespace="/" extends="struts-default">
        <default-action-ref name="error"></default-action-ref>
        <action name="error">
            <result>/error.jsp</result>
        </action>
......
</packge>

Add url suffix

The default suffix of action is .action, this suffix can be written or not when accessing the url. In the struts configuration file, add the suffix to the access page through the constant struts.action.extension. For example, if the suffix is ​​set to html, then all urls must be added with .html to access normally.

    <constant name="struts.action.extension" value="html"></constant>

Receive parameters

In addition to using request to receive the parameters in the request, you can also receive the parameters in the front-end page through the following three methods

The first is to receive it directly through the Action attribute . Define the attribute variable in the Action class and implement its get / set method, and then you can use the attribute variable directly in the action method. For example, the front-end form submission has two parameters named username and password. Define the corresponding variables and get / set methods in LoginAction, and then you can directly get the two parameter values ​​in the login () method.

  <form action="login.action" method="post">
    姓名:<input type="text" name="username">
    密码:<input type="password" name="password">
    <input type="submit" value="提交">
  </form>
public class LoginAction extends ActionSupport {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String login(){
        System.out.println(username+":"+password);      //直接通过Action属性获取参数
        return SUCCESS;
    }
}

Putting properties directly in the action class is not conducive to the encapsulation and management of objects. The second method, DomainModel , uses objects to receive parameters. Create a new JavaBean class User to store the username and password attributes, and then instantiate a user object in the action and define the set / get method. When setting the property name in the front-end form, add the object name user, which is user.username, user.password. In this way, the attribute will be automatically assigned to the action file, and the user object can be used directly.

//JavaBean类User
public class User {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

//Action中使用user对象接收参数
public class LoginAction extends ActionSupport {
    private User user;        //新建user对象

    public User getUser() {    //设置get方法
        return user;
    }

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

    public String login(){            //通过User对象获取参数
        System.out.println(user.getUsername()+":"+user.getPassword());      
        return SUCCESS;
    }
}

  <form action="login.action" method="post">
    姓名:<input type="text" name="user.username">    <!--通过user对象传递属性-->
    密码:<input type="password" name="user.password">
    <input type="submit" value="提交">
  </form>

The third method is to use the ModelDriven interface. The Action class implements the ModelDriven interface and implements its getModel () method to obtain the user object. In this way, there is no need to define the get / set method of the user object, and the front page form attribute does not need to add the user object prefix, which reduces the coupling. This method is recommended.

public class LoginAction extends ActionSupport implements ModelDriven<User> {    //实现接口
    private User user=new User();            //需要实例化user对象

    @Override
    public User getModel() {                //实现接口方法
        return user;
    }

    public String login(){                    //可以使用user对象获取参数
        System.out.println(user.getUsername()+":"+user.getPassword());      
        return SUCCESS;
    }
}
  <form action="login.action" method="post">
    姓名:<input type="text" name="username">    <!--不必添加user对象前缀-->
    密码:<input type="password" name="password">
    <input type="submit" value="提交">
  </form>

Result

The <result> tag will match different name attributes according to the different String strings returned by the action, so as to execute different result sets, which is more conducive to the separation between the framework modules. Before returning SUCCESS to represent the string "success", struts has other default strings:

The parameters passed on the front end cannot match the variables received in the action. The action will automatically return to INPUT, or you can manually return to INPUT. For example, to judge the received username, if it is empty, add FiledError and return INPUT. You can display the fielderro tag through struts-tags on the front-end page. When the action throws FieldError and returns INPUT and jumps back to login.jsp again, the fielderror tag will display the error information in FieldError.

public class LoginAction extends ActionSupport implements ModelDriven<User> {
    private User user=new User();

    @Override
    public User getModel() {
        return user;
    }

    public String login(){
        if (user.getUsername()==null||user.getUsername().isEmpty()) {
            this.addFieldError("username", "用户名不能为空");      //添加错误信息
            return INPUT;
        }
        System.out.println(user.getUsername()+":"+user.getPassword());  
        return SUCCESS;
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>                       <!--引入struts-tags标签-->
<html>
  <head>
    <title>登录界面</title>
  </head>
  <body>
  <form action="login.action" method="post">
    姓名:<input type="text" name="username"><s:fielderror name="username"/>    <!--错误提示-->
    密码:<input type="password" name="password">
    <input type="submit" value="提交">
  </form>
  </body>
</html>

As shown below, struts-tags displays prompt information:

According to the position of the <result> tag, the result view can be divided into local results and global results. If <result> is directly defined in the <global-result> tag, it is a global result . If <result> is defined in <action>, it is a partial result.

<package>    
    <global-results>
        <result name="404error">/404.jsp</result>
    </global-results>
    ......
</package>

The attribute type of <result> can specify the type of the returned result. The default is JSP. You can also use other template engines such as Valocity and FreeMarker. It also supports redirect and plain text.

Interceptor

In the struts schematic diagram, you can see that the interceptor (Interceptor) acts on the request before it reaches the Action, and then returns through the interceptor after returning the Result result. Multiple interceptors form an interceptor stack, and the execution of the interceptor stack is in order, just like the stack, and comes out first. So we can use an interceptor to pre-process the request before it reaches the action, and perform further operations before returning the result.

 Define interceptor

The first method is to implement the Interceptor interface. The interface has three methods:

  • init () initializes the resources required by the interceptor
  • destroy () releases allocated resources
  • String intercept (ActionInvocation ai), obtain the action status through ActionInvocation, complete the main operation of the interceptor, and return the Result string

The second method is to inherit the AbstractInterceptor class, which provides empty implementations of the init () and destroy () methods, so we only need to implement the intercept () method, so this method is more commonly used. Define an interceptor to verify user login as shown below. If username is not empty in the session, the interceptor will pass to the next layer, otherwise it will return the string “login” and jump to the login interface.

public class AuthLog extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        System.out.println("Action执行之前");
        ActionContext actionContext=ActionContext.getContext();
        Map session =actionContext.getSession();
        if (session.get("username")!=null){
            //执行下一个拦截器,若为最后一个则执行目标Action,然后返回结果
            String result=actionInvocation.invoke();
            System.out.println("执行Action之后");
            //将结果返回上一层
            return result;
        }else {
            return "login";
        }
    }
}

Register interceptor

First register the interceptor in the struts.xml file, and then reference the interceptor in the action to be used. It is also possible to combine multiple interceptors into one interceptor stack.

As shown below, first define an interceptor authlog, pointing to the AuthLog class. Then it is combined with the default interceptor as the myStack interceptor stack. Then define action as personalPage and add interceptor myStack to it. When the user accesses the action, it will first pass the defaultStack in the myStack interceptor stack, and then pass the authlog interceptor, where the login verification is completed, and if the verification is successful, return success.jsp, otherwise return login.jsp.

        <interceptors>
            <interceptor name="authlog" class="interceptor.AuthLog"></interceptor>
            <!--定义拦截器栈-->
            <interceptor-stack name="myStack">
            <interceptor-ref name="defaultStack"></interceptor-ref>     <!--引用默认拦截器-->
                <interceptor-ref name="authlog"></interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <action name="personalPage">
            <result>/success.jsp</result>
            <result name="login">/login.jsp</result>
            <interceptor-ref name="myStack"></interceptor-ref>          <!--引用拦截器-->
        </action>

Built-in interceptor

There are many interceptors built into struts to achieve its functions:

  • The params interceptor passes the requested params parameter to the action attribute. Previously, the action was used to directly receive the params attribute through this interceptor.
  • The servletConfig interceptor injects the servlet's interface into the action, so that request, session and other servlet objects can be used in the action
  • The fileUpload interceptor provides support for file uploads, setting files and metadata to action attributes
  • The exception interceptor catches exceptions and maps to user-defined pages
  • The validation interceptor performs data verification through the verification framework

These interceptors are registered in the struts-default.xml file in the struts-core.jar package and are collectively packaged as the default interceptor stack <interceptor-stack name = "defaultStack">. And set to the default reference <default-interceptor-ref name = "defaultStack" />, that is, if the user does not reference the interceptor, the default interceptor stack defaultStack will be referenced. However, if the user customizes the interceptor, the defaultStack will no longer be referenced, so manual reference is required.

 

Published 124 original articles · Like 65 · Visit 130,000+

Guess you like

Origin blog.csdn.net/theVicTory/article/details/104816050