Struts2初始

第一章 使用Filter作为控制器的MVC

1.1 MVC设计模式概览

在这里插入图片描述

1.2 实例项目

项目需求

在这里插入图片描述

项目结构

在这里插入图片描述
FilterDispatcher

package com.atguigu.struts2.helloworld;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @Author :
 * @Date :Created in 2023/3/20 13:49
 * @Description:
 */
public class FilterDispatcher implements Filter {

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws javax.servlet.ServletException, IOException {

        HttpServletRequest req=(HttpServletRequest) request;
        //1. 获取 servletPath
        String servletPath = req.getServletPath();
        System.out.println(servletPath);

        String path = null;

        //2. 判断 servletPath, 若其等于 "/product-input.action", 则转发到
        ///WEB-INF/pages/input.jsp
        if("/product-input.action".equals(servletPath)){
            path = "/WEB-INF/pages/input.jsp";
        }

        //3. 若其等于 "/product-save.action", 则
        if("/product-save.action".equals(servletPath)){
            //1). 获取请求参数
            String productName = request.getParameter("productName");
            String productDesc = request.getParameter("productDesc");
            String productPrice = request.getParameter("productPrice");

            //2). 把请求信息封装为一个 Product 对象
            Product product = new Product(null, productName, productDesc, Double.parseDouble(productPrice));

            //3). 执行保存操作
            System.out.println("Save Product: " + product);
            product.setProductId(1001);

            //4). 把 Product 对象保存到 request 中. ${param.productName} -> ${requestScope.product.productName}
            request.setAttribute("product", product);

            path = "/WEB-INF/pages/details.jsp";
        }

        if(path != null){
            request.getRequestDispatcher(path).forward(request, response);
            return;
        }

        chain.doFilter(request, response);
    }

    @Override
    public void init(javax.servlet.FilterConfig config) throws javax.servlet.ServletException {

    }

}

Product

package com.atguigu.struts2.helloworld;

public class Product {
	
	private Integer productId;
	private String productName;
	private String productDesc;
	
	private double productPrice;

	public Integer getProductId() {
		return productId;
	}

	public void setProductId(Integer productId) {
		this.productId = productId;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getProductDesc() {
		return productDesc;
	}

	public void setProductDesc(String productDesc) {
		this.productDesc = productDesc;
	}

	public double getProductPrice() {
		return productPrice;
	}

	public void setProductPrice(double productPrice) {
		this.productPrice = productPrice;
	}

	public Product(Integer productId, String productName, String productDesc,
			double productPrice) {
		super();
		this.productId = productId;
		this.productName = productName;
		this.productDesc = productDesc;
		this.productPrice = productPrice;
	}
	
	public Product() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public String toString() {
		return "Product [productId=" + productId + ", productName="
				+ productName + ", productDesc=" + productDesc
				+ ", productPrice=" + productPrice + "]";
	}
	
	
}

detail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	ProductId: ${requestScope.product.productId }
	<br><br>

	ProductName: ${requestScope.product.productName }
	<br><br>
	
	ProductDesc: ${requestScope.product.productDesc }
	<br><br>
	
	ProductPrice: ${requestScope.product.productPrice }
	<br><br>
	
</body>
</html>

input.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<form action="product-save.action" method="post">
		
		ProductName: <input type="text" name="productName"/>
		<br><br>

		ProductDesc: <input type="text" name="productDesc"/>
		<br><br>
		
		ProductPrice: <input type="text" name="productPrice" />
		<br><br>
		
		<input type="submit" value="Submit"/>
		<br><br>
	
	</form>

</body>
</html>

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: 
  Date: 2023/3/20
  Time: 13:45
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <a href="product-input.action">Product Input</a>
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-1</display-name>
    <filter>
        <filter-name>FilterDispatcher</filter-name>
        <filter-class>com.atguigu.struts2.helloworld.FilterDispatcher</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterDispatcher</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

1.3 使用Filter作为控制器的好处

在这里插入图片描述

第二章 Hello Struts2

2.1 Struts2概述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
本质来说:Struts2与Struts1没有任何关系,当时为了Struts2的发展,所以说成了是Struts1的升级,就像一个刚出道的品牌,如果说成了是香奈儿的分支,卖的会更好。Struts2说成了Struts1的升级只是一种Struts2的推广和营销手段。
在这里插入图片描述

2.2 项目实例

在这里插入图片描述
在这里插入图片描述

Product.java

package com.atguigu.struts2.helloworld;

public class Product {
	
	private Integer productId;
	private String productName;
	private String productDesc;
	
	private double productPrice;

	public Integer getProductId() {
		return productId;
	}

	public void setProductId(Integer productId) {
		this.productId = productId;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getProductDesc() {
		return productDesc;
	}

	public void setProductDesc(String productDesc) {
		this.productDesc = productDesc;
	}

	public double getProductPrice() {
		return productPrice;
	}

	public void setProductPrice(double productPrice) {
		this.productPrice = productPrice;
	}

	@Override
	public String toString() {
		return "Product [productId=" + productId + ", productName="
				+ productName + ", productDesc=" + productDesc
				+ ", productPrice=" + productPrice + "]";
	}
	
	public String save(){
		System.out.println("save: " + this);
		return "details";
	}
	
	public String test(){
		System.out.println("test");
		return "success";
	}
	
	public Product() {
		System.out.println("Product's constructor...");
	}
	
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>


	<!--
		package: 包. struts2 使用 package 来组织模块.
		name 属性: 必须. 用于其它的包应用当前包.
		extends: 当前包继承哪个包, 继承的, 即可以继承其中的所有的配置. 通常情况下继承 struts-default
		         struts-default 这个包在 struts-default.xml 文件中定义.
		namespace 可选, 如果它没有给出, 则以 / 为默认值.
		                        若 namespace 有一个非默认值, 则要想调用这个包里的Action,
		                        就必须把这个属性所定义的命名空间添加到有关的 URI 字符串里

		          http://localhost:8080/contextPath/namespace/actionName.action
	-->
    <package name="helloWorld" extends="struts-default">

    	<!--
    		配置一个 action: 一个 struts2 的请求就是一个 action
    		name: 对应一个 struts2 的请求的名字(或对一个 servletPath, 但去除 / 和扩展名), 不包含扩展名
    		class 的默认值为: com.opensymphony.xwork2.ActionSupport
    		method 的默认值为: execute
    		result: 结果.
    	-->
    	<action name="product-input"
    		class="com.opensymphony.xwork2.ActionSupport"
    		method="execute">
    		<!--
    			result: 结果. 表示 action 方法执行后可能返回的一个结果. 所以一个 action 节点可能会有多个 result 子节点.
    			多个 result 子节点使用 name 来区分
    			name: 标识一个 result. 和 action 方法的返回值对应. 默认值为 success
    			type: 表示结果的类型. 默认值为 dispatcher(转发到结果.)
    		-->
    		<result name="success" type="dispatcher">/WEB-INF/pages/input.jsp</result>
    	</action>

    	<action name="product-save" class="com.atguigu.struts2.helloworld.Product"
    		method="save">
    		<result name="details">/WEB-INF/pages/details.jsp</result>
    	</action>

    	<action name="test" class="com.atguigu.struts2.helloworld.Product" method="test">
    		<result>/index.jsp</result>
    	</action>

    </package>

</struts>

details.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<% 
		request.setCharacterEncoding("UTF-8");
	%>
	
	ProductId: ${productId }
	<br><br>

	ProductName: ^<%= request.getAttribute("productName") %>
	<br><br>
	
	ProductDesc: ${productDesc }
	<br><br>
	
	ProductPrice: ${productPrice }
	<br><br>
	
	ProductPrice: ^<s:property value="productPrice"/>
	<br><br>
	
	<%= request %>
	
</body>
</html>

input.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<form action="product-save.action" method="post">
		
		ProductName: <input type="text" name="productName"/>
		<br><br>

		ProductDesc: <input type="text" name="productDesc"/>
		<br><br>
		
		ProductPrice: <input type="text" name="productPrice" />
		<br><br>
		
		<input type="submit" value="Submit"/>
		<br><br>
	
	</form>

</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-2</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<a href="product-input.action">Product Input</a>
	
	<br><br>
	
	<a href="test.action">Test</a>
</body>
</html>

note.txt

1. VS 自实现:

1). 搭建 Struts2 的开发环境

2). 不需要显式的定义 Filter, 而使用的是 struts2 的配置文件. 

3). details.jsp 比先前变得简单了.

${requestScope.product.productName} -> ${productName}

4). 步骤:

I.  由 product-input.action 转到 /WEB-INF/pages/input.jsp
	
	在 struts2 中配置一个 action
	
	<action name="product-input">
		<result>/WEB-INF/pages/input.jsp</result>
	</action>
	
II. 由 input.jsp 页面的 action: product-save.action 到 Product's save, 再到  /WEB-INF/pages/details.jsp

	<action name="product-save" class="com.atguigu.struts2.helloworld.Product"
		method="save">
		<result name="details">/WEB-INF/pages/details.jsp</result>	
	</action>
	
	在 Prodcut 中定义一个 save 方法, 且返回值为 details

struts-default.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!--
/*
 * $Id: struts-default.xml 1485719 2013-05-23 14:12:24Z lukaszlenart $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
-->
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" />
    <bean type="com.opensymphony.xwork2.ObjectFactory" name="struts" class="org.apache.struts2.impl.StrutsObjectFactory" />

    <bean type="com.opensymphony.xwork2.FileManager" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" name="system" scope="singleton"/>

    <bean type="com.opensymphony.xwork2.FileManagerFactory" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" name="xwork" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.FileManagerFactory" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" name="struts" scope="singleton"/>

    <bean type="com.opensymphony.xwork2.ActionProxyFactory" name="xwork" class="com.opensymphony.xwork2.DefaultActionProxyFactory"/>
    <bean type="com.opensymphony.xwork2.ActionProxyFactory" name="struts" class="org.apache.struts2.impl.StrutsActionProxyFactory"/>

    <bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="tiger" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>
    <bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="notiger" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>
    <bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>

    <bean type="com.opensymphony.xwork2.util.PatternMatcher" name="struts" class="com.opensymphony.xwork2.util.WildcardHelper" />
    <bean type="com.opensymphony.xwork2.util.PatternMatcher" name="namedVariable" class="com.opensymphony.xwork2.util.NamedVariablePatternMatcher"/>
    <bean type="com.opensymphony.xwork2.util.PatternMatcher" name="regex" class="org.apache.struts2.util.RegexPatternMatcher"/>

    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="struts" class="org.apache.struts2.dispatcher.mapper.DefaultActionMapper" />
    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="composite" class="org.apache.struts2.dispatcher.mapper.CompositeActionMapper" />
    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="restful" class="org.apache.struts2.dispatcher.mapper.RestfulActionMapper" />
    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="restful2" class="org.apache.struts2.dispatcher.mapper.Restful2ActionMapper" />

    <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="struts" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default"/>
    <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default" />
    <constant name="struts.multipart.parser" value="jakarta" />

    <bean type="org.apache.struts2.views.TagLibrary" name="s" class="org.apache.struts2.views.DefaultTagLibrary" />

    <bean class="org.apache.struts2.views.freemarker.FreemarkerManager" name="struts" />
    <bean class="org.apache.struts2.views.velocity.VelocityManager" name="struts" optional="true" />

    <bean class="org.apache.struts2.components.template.TemplateEngineManager" />
    <bean type="org.apache.struts2.components.template.TemplateEngine" name="ftl" class="org.apache.struts2.components.template.FreemarkerTemplateEngine" />
    <bean type="org.apache.struts2.components.template.TemplateEngine" name="vm" class="org.apache.struts2.components.template.VelocityTemplateEngine" />
    <bean type="org.apache.struts2.components.template.TemplateEngine" name="jsp" class="org.apache.struts2.components.template.JspTemplateEngine" />

    <bean type="com.opensymphony.xwork2.conversion.impl.XWorkConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.XWorkConverter" />
    <bean type="com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionPropertiesProcessor" />
    <bean type="com.opensymphony.xwork2.conversion.ConversionFileProcessor" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor" />
    <bean type="com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor" />
    <bean type="com.opensymphony.xwork2.conversion.TypeConverterCreator" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator" />
    <bean type="com.opensymphony.xwork2.conversion.TypeConverterHolder" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder" />

    <bean class="com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter" />

    <bean type="com.opensymphony.xwork2.conversion.impl.CollectionConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.CollectionConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.ArrayConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.ArrayConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.DateConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.DateConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.NumberConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.NumberConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.StringConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.StringConverter" scope="singleton"/>

    <bean type="com.opensymphony.xwork2.TextProvider" name="struts" class="com.opensymphony.xwork2.TextProviderSupport" scope="default" />
    <bean type="com.opensymphony.xwork2.LocaleProvider" name="struts" class="com.opensymphony.xwork2.DefaultLocaleProvider" scope="singleton" />

    <bean type="org.apache.struts2.components.UrlRenderer" name="struts" class="org.apache.struts2.components.ServletUrlRenderer"/>
    <bean type="org.apache.struts2.views.util.UrlHelper" name="struts" class="org.apache.struts2.views.util.DefaultUrlHelper"/>

    <bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="struts" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" />
    <bean type="com.opensymphony.xwork2.util.reflection.ReflectionProvider" name="struts" class="com.opensymphony.xwork2.ognl.OgnlReflectionProvider" />
    <bean type="com.opensymphony.xwork2.util.reflection.ReflectionContextFactory" name="struts" class="com.opensymphony.xwork2.ognl.OgnlReflectionContextFactory" />

    <bean type="com.opensymphony.xwork2.TextProvider" name="system" class="com.opensymphony.xwork2.DefaultTextProvider" />
    <bean type="com.opensymphony.xwork2.conversion.NullHandler" name="java.lang.Object" class="com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler" />

    <bean type="com.opensymphony.xwork2.validator.ActionValidatorManager" name="struts" class="com.opensymphony.xwork2.validator.AnnotationActionValidatorManager" />
    <bean type="com.opensymphony.xwork2.validator.ActionValidatorManager" name="no-annotations" class="com.opensymphony.xwork2.validator.DefaultActionValidatorManager" />

    <bean type="com.opensymphony.xwork2.validator.ValidatorFactory" class="com.opensymphony.xwork2.validator.DefaultValidatorFactory"/>
    <bean type="com.opensymphony.xwork2.validator.ValidatorFileParser" class="com.opensymphony.xwork2.validator.DefaultValidatorFileParser" />

    <bean class="com.opensymphony.xwork2.ognl.OgnlUtil" />

    <bean type="com.opensymphony.xwork2.util.TextParser" name="struts" class="com.opensymphony.xwork2.util.OgnlTextParser" scope="singleton"/>

    <bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.ObjectAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Iterator" class="com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Enumeration" class="com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.List" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Set" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Map" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Collection" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.ognl.ObjectProxy" class="com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor" />

    <bean type="ognl.MethodAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor" />
    <bean type="ognl.MethodAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />

    <bean class="org.apache.struts2.views.jsp.ui.OgnlTool" />

    <bean type="org.apache.struts2.dispatcher.StaticContentLoader" class="org.apache.struts2.dispatcher.DefaultStaticContentLoader" name="struts" />
    <bean type="com.opensymphony.xwork2.UnknownHandlerManager" class="com.opensymphony.xwork2.DefaultUnknownHandlerManager" name="struts" />

    <!--  Silly workarounds for OGNL since there is currently no way to flush its internal caches -->
    <bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.HashMap" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />

    <package name="struts-default" abstract="true">
        <result-types>
            <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
            <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
            <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
            <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
            <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
            <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
            <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
            <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
            <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
            <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
        </result-types>

        <interceptors>
            <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
            <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
            <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
            <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
            <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
            <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
            <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
            <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
            <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
            <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
            <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
            <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
            <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
            <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
            <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
            <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
            <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
            <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
            <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
            <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
            <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
            <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
            <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
            <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
            <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
            <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
            <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
            <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
            <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
            <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
            <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
            <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
            <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />

            <!-- Basic stack -->
            <interceptor-stack name="basicStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
            </interceptor-stack>

            <!-- Sample validation and workflow stack -->
            <interceptor-stack name="validationWorkflowStack">
                <interceptor-ref name="basicStack"/>
                <interceptor-ref name="validation"/>
                <interceptor-ref name="workflow"/>
            </interceptor-stack>

            <!-- Sample file upload stack -->
            <interceptor-stack name="fileUploadStack">
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample model-driven stack  -->
            <interceptor-stack name="modelDrivenStack">
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample action chaining stack -->
            <interceptor-stack name="chainStack">
                <interceptor-ref name="chain"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample i18n stack -->
            <interceptor-stack name="i18nStack">
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- An example of the paramsPrepareParams trick. This stack
                 is exactly the same as the defaultStack, except that it
                 includes one extra interceptor before the prepare interceptor:
                 the params interceptor.

                 This is useful for when you wish to apply parameters directly
                 to an object that you wish to load externally (such as a DAO
                 or database or service layer), but can't load that object
                 until at least the ID parameter has been loaded. By loading
                 the parameters twice, you can retrieve the object in the
                 prepare() method, allowing the second params interceptor to
                 apply the values on the object. -->
            <interceptor-stack name="paramsPrepareParamsStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
            </interceptor-stack>

            <!-- A complete stack with all the common interceptors in place.
                 Generally, this stack should be the one you use, though it
                 may do more than you need. Also, the ordering can be
                 switched around (ex: if you wish to have your servlet-related
                 objects applied before prepare() is called, you'd need to move
                 servletConfig interceptor up.

                 This stack also excludes from the normal validation and workflow
                 the method names input, back, and cancel. These typically are
                 associated with requests that should not be validated.
                 -->
            <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
            </interceptor-stack>

            <!-- The completeStack is here for backwards compatibility for
                 applications that still refer to the defaultStack by the
                 old name -->
            <interceptor-stack name="completeStack">
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>

            <!-- Sample execute and wait stack.
                 Note: execAndWait should always be the *last* interceptor. -->
            <interceptor-stack name="executeAndWaitStack">
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
            </interceptor-stack>

       </interceptors>

        <default-interceptor-ref name="defaultStack"/>

        <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
    </package>

</struts>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第三章 Action

3.1 Action介绍

在这里插入图片描述

3.2 访问web资源

在这里插入图片描述

与Servlet API解耦的访问方式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

与Servlet耦合的方式

在这里插入图片描述

3.3 ActionSupport

在这里插入图片描述

3.4 代码总结

在这里插入图片描述

note.txt

1. 复习搭建 Struts2 的开发环境: 3 个步骤

2. action VS Action 类
1). action: 代表一个  Struts2 的请求.
2). Action 类: 能够处理 Struts2 请求的类.
	> 属性的名字必须遵守与 JavaBeans 属性名相同的命名规则. 
	    属性的类型可以是任意类型. 从字符串到非字符串(基本数据库类型)之间的数据转换可以自动发生
	> 必须有一个不带参的构造器: 通过反射创建实例
	> 至少有一个供 struts 在执行这个 action 时调用的方法
	> 同一个 Action 类可以包含多个 action 方法.
	> Struts2 会为每一个 HTTP 请求创建一个新的 Action 实例, 即 Action 不是单例的, 是线程安全的.

2. 在 Action 中访问 WEB 资源:
1). 什么是 WEB 资源 ?
	HttpServletRequest, HttpSession, ServletContext 等原生的 Servlet API。
2). 为什么访问 WEB 资源?
	B\S 的应用的 Controller 中必然需要访问 WEB 资源: 向域对象中读写属性, 读写 Cookie, 获取 realPath ....
3). 如何访问 ?
I. 和 Servlet API 解耦的方式: 只能访问有限的 Servlet API 对象, 且只能访问其有限的方法(读取请求参数, 读写域对象的属性, 使 session 失效...).
	> 使用 ActionContext
	> 实现 XxxAware 接口
	> 选用的建议: 若一个 Action 类中有多个 action 方法, 且多个方法都需要使用域对象的 Map 或 parameters, 则建议使用
	Aware 接口的方式
	> session 对应的 Map 实际上是 SessionMap 类型的! 强转后若调用其 invalidate() 方法, 可以使其 session 失效!
II. 和 Servlet API 耦合的方式: 可以访问更多的 Servlet API 对象, 且可以调用其原生的方法.
	> 使用 ServletActionContext
	> 实现 ServletXxxAware 接口.

3. 关于 Struts2 请求的扩展名问题
1). org.apache.struts2 包下的 default.properties 中配置了 Struts2 应用个的一些常量
2). struts.action.extension 定义了当前 Struts2 应用可以接受的请求的扩展名.
3). 可以在 struts.xml 文件中以常量配置的方式修改 default.properties 所配置的常量.
<constant name="struts.action.extension" value="action,do,"></constant>

4. ActionSupport
1). ActionSupport 是默认的 Action 类: 若某个 action 节点没有配置 class 属性, 则 ActionSupport 即为
待执行的 Action 类. 而 execute 方法即为要默认执行的 action 方法
<action name="testActionSupport">
	<result>/testActionSupport.jsp</result>
</action>
等同于
<action name="testActionSupport"
	class="com.opensymphony.xwork2.ActionSupport"
	method="execute">
	<result>/testActionSupport.jsp</result>
</action>
2). 在手工完成字段验证, 显示错误消息, 国际化等情况下, 推荐继承 ActionSupport.

TestActionContextAction.java

package com.atguigu.struts2.action;

import com.opensymphony.xwork2.ActionContext;
import org.apache.struts2.dispatcher.SessionMap;

import java.util.Map;

/**
 * @Author :
 * @Date :Created in 2023/3/27 9:37
 * @Description:
 */
public class TestActionContextAction {

    public String execute(){

        //0. 获取 ActionContext 对象
        //ActionContext 是 Action 的上下文对象. 可以从中获取到当往 Action 需要的一切信息
        ActionContext actionContext = ActionContext.getContext();

        //1. 获取 application 对应的 Map, 并向其中添加一个属性
        //通过调用 ActionContext 对象的 getApplication() 方法来获取 application 对象的 Map 对象
        Map<String, Object> applicationMap = actionContext.getApplication();
        //设置属性
        applicationMap.put("applicationKey", "applicationValue");

        //获取属性
        Object date = applicationMap.get("date");
        System.out.println("date: " + date);

        //2. session
        Map<String, Object> sessionMap = actionContext.getSession();
        sessionMap.put("sessionKey", "sessionValue");

        System.out.println(sessionMap.getClass());

        if(sessionMap instanceof SessionMap){
            SessionMap sm = (SessionMap) sessionMap;
            sm.invalidate();
            System.out.println("session 失效了. ");
        }

        //3. request*
        //ActionContext 中并没有提供 getRequest 方法来获取 request 对应的 Map
        //需要手工调用 get() 方法, 传入 request 字符串来获取.
        Map<String, Object> requestMap = (Map<String, Object>) actionContext.get("request");
        requestMap.put("requestKey", "requestValue");

        //4. 获取请求参数对应的 Map, 并获取指定的参数值.
        //键: 请求参数的名字, 值: 请求参数的值对应的字符串数组
        //注意: 1. getParameters 的返回值为在 Map<String, Object>, 而不是 Map<String, String[]>
        //     2. parameters 这个 Map 只能读, 不能写入数据, 如果写入, 但不出错, 但也不起作用!
        Map<String, Object> parameters = actionContext.getParameters();
        System.out.println(((String[])parameters.get("name"))[0]);

        parameters.put("age", 100);

        return "success";
    }

}

TestActionSupport.java

package com.atguigu.struts2.action;

import com.opensymphony.xwork2.ActionSupport;

public class TestActionSupport extends ActionSupport {

	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		return SUCCESS;
	}
	
}

TestAwareAction.java

package com.atguigu.struts2.action;

import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.ParameterAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

import java.util.Map;

/**
 * @Author :
 * @Date :Created in 2023/3/28 9:42
 * @Description:
 */
public class TestAwareAction implements ApplicationAware, SessionAware, RequestAware, ParameterAware {

    private Map<String,Object> application;

    public String execute(){
        //1. 向 application 中加入一个属性: applicationKey2 - applicationValue2
        application.put("applicationKey2", "applicationValue2");

        //2. 从 application 中读取一个属性 date, 并打印.
        System.out.println(application.get("date"));

        return "success";
    }

    @Override
    public void setApplication(Map<String, Object> application) {
        this.application=application;
    }

    @Override
    public void setParameters(Map<String, String[]> parameters) {

    }

    @Override
    public void setRequest(Map<String, Object> request) {
        // TODO Auto-generated method stub

    }

    @Override
    public void setSession(Map<String, Object> session) {
        // TODO Auto-generated method stub

    }
}

TestServletActionContextAction.java

package com.atguigu.struts2.action;

import org.apache.struts2.ServletActionContext;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @Author :
 * @Date :Created in 2023/3/28 13:59
 * @Description:
 */
public class TestServletActionContextAction {

    /**
     * ServletActionContext:可以从中获取到当前Action对象需要的一切ServletAPI相关对象
     * 常用的方法:
     *  1. 获取HttpServletRequest:ServletActionContext.getRequest();
     *  2. 获取HttpSession:ServletActionContext.getRequest().getSession();
     *  3. 获取ServletContext:ServletActionContext.getServletContext();
     * @return
     */
    public String execute() {
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = ServletActionContext.getRequest().getSession();
        ServletContext servletContext = ServletActionContext.getServletContext();

        System.out.println("execute...");

        return "success";
    }

}

TestServletAwareAction.java

package com.atguigu.struts2.action;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.util.ServletContextAware;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 通过实现ServletXxxAware接口的方式可以由Struts2注入需要的Servlet相关的对象
 * ServletRequestAware:注入httpServletRequest对象
 * ServletContextAware:注入servletContext对象
 * ServletResponseAware:注入httpServletResponse对象
 */
public class TestServletAwareAction implements ServletRequestAware, ServletContextAware, ServletResponseAware {

    @Override
    public void setServletRequest(HttpServletRequest httpServletRequest) {
        System.out.println(httpServletRequest);
    }

    @Override
    public void setServletResponse(HttpServletResponse httpServletResponse) {
        System.out.println(httpServletResponse);
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        System.out.println(servletContext);
    }

    public String execute() {
        return "success";
    }
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<package name="default" namespace="/" extends="struts-default">
		<action name="TestActionContext"
				class="com.atguigu.struts2.action.TestActionContextAction"
		        method="execute">
			<result name="success" type="dispatcher">/test-actionContext.jsp</result>
		</action>
		<action name="TestAwareAction"
				class="com.atguigu.struts2.action.TestAwareAction"
				method="execute">
			<result name="success" type="dispatcher">/test-aware.jsp</result>
		</action>
		<action name="TestServletActionContextAction"
				class="com.atguigu.struts2.action.TestServletActionContextAction"
				method="execute">
			<result name="success" type="dispatcher">/success.jsp</result>
		</action>
		<action name="TestServletAwareAction"
				class="com.atguigu.struts2.action.TestServletAwareAction"
				method="execute">
			<result name="success" type="dispatcher">/success.jsp</result>
		</action>
		<action name="testActionSupport">
			<result>/testActionSupport.jsp</result>
		</action>
	</package>

</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-2</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

index.jsp

<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<a href="TestActionContext.action?name=atguigu">Test ActionContext</a>
	<br><br>
	<a href="TestAwareAction.do?name=atguigu">Test Aware</a>
	<br><br>
	<a href="TestServletActionContextAction.action?name=atguigu">Test ServletActionContext</a>
	<br><br>
	<a href="TestServletAwareAction.action?name=atguigu">Test ServletAware</a>
	<br><br>
	<a href="testActionSupport.do">Test ActionSupport</a>
	<br><br>

	<%
		if (application.getAttribute("date")==null) {
			application.setAttribute("date",new Date());
		}
	%>


</body>
</html>

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<h4>Success Page</h4>
	
</body>
</html>

test-actionContext.jsp

<%--
  Created by IntelliJ IDEA.
  User: 
  Date: 2023/3/27
  Time: 9:45
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h4>Test ActionContext Page</h4>
    application:${applicationScope.applicationKey}
    <br><br>
    session:${sessionScope.sessionKey}
    <br><br>
    request:${requestScope.requestKey}
    <br><br>
    age: ${parameters.age }
</body>
</html>

test-aware.jsp

<%--
  Created by IntelliJ IDEA.
  User: 
  Date: 2023/3/28
  Time: 9:43
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h4>Test Aware Page</h4>

    application: ${applicationScope.applicationKey2}
</body>
</html>

testActionSupport.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<h4>Test ActionSupport Page</h4>
	
</body>
</html>

第四章 练习

在这里插入图片描述
在这里插入图片描述
UserAction.java

package com.atguigu.struts2.action;

import org.apache.struts2.dispatcher.SessionMap;
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.SessionAware;

import java.util.Map;

/**
 * @Author :
 * @Date :Created in 2023/3/29 18:52
 * @Description:
 */
public class UserAction implements SessionAware, ApplicationAware {

    private Map<String,Object> session=null;

    private Map<String,Object> aplication=null;

    private String username;

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

    @Override
    public void setSession(Map<String, Object> map) {
        this.session=map;
    }

    @Override
    public void setApplication(Map<String, Object> map) {
        this.aplication=map;
    }

    public String execute() {
        //把用户信息存入Session域中
        //1.获取session.通过实现SessionAware接口

        //2.获取登录信息:通过在Action中添加setter方法

        //3.把用户信息存入Session域中
        session.put("username",username);

        //在线人数+1
        //1.获取当前的在线人数
        Integer count=(Integer)aplication.get("count");
        if(count==null){
            count=0;
        }

        //2.使当前的在线人数+ 1
        count++;

        aplication.put("count",count);


        return "login-success";
    }

    public String logout() {
        //1. 在线人数- 1:获取在线人数,若数量还>0,则- 1
        Integer count=(Integer)aplication.get("count");
        if(count!=null&&count>0){
            count--;
            aplication.put("count",count);
        }

        //2. session失效:强转为SessionMap,调用invalidate方法
        ((SessionMap)session).invalidate();

        return "logout-success";
    }

}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<!--打开允许动态方法调用的开关,默认是false-->
	<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

	<package name="default" namespace="/" extends="struts-default">
		<action name="login-ui">
			<result>/login.jsp</result>
		</action>
		<action name="user-login" class="com.atguigu.struts2.action.UserAction" method="execute">
			<result name="login-success" type="dispatcher">/login-success.jsp</result>
		</action>
		<action name="logout" class="com.atguigu.struts2.action.UserAction" method="logout">
			<result name="logout-success" type="dispatcher">/login.jsp</result>
		</action>
	</package>
</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-2</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

index.jsp

<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<a href="login-ui.do">LoginUI</a>



</body>
</html>

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<form action="user-login.do" method="post">
		username:<input type="text" name="username">
		<input type="submit" value="Login">
	</form>
	
</body>
</html>

login-success.jsp

<%--
  Created by IntelliJ IDEA.
  User: 
  Date: 2023/3/29
  Time: 19:04
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    Welcome:${sessionScope.username}
    <br><br>
    Count One Line:${applicationScope.count}
    <br><br>
    <a href="logout.do">logout</a>
</body>
</html>

第五章 result与动态方法调用

5.1 result

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2 动态方法调用

在这里插入图片描述

5.3 代码总结

在这里插入图片描述

note.txt

5. result:
1). result 是 action 节点的子节点
2). result 代表 action 方法执行后, 可能去的一个目的地
3). 一个 action 节点可以配置多个 result 子节点.
4). result 的 name 属性值对应着 action 方法可能有的一个返回值.
<result name="index">/index.jsp</result>
5). result 一共有 2 个属性, 还有一个是 type: 表示结果的响应类型
6). result 的 type 属性值在 struts-default 包的 result-types 节点的 name 属性中定义.
         常用的有
    > dispatcher(默认的): 转发. 同 Servlet 中的转发.
    > redirect: 重定向
    > redirectAction: 重定向到一个 Action
    	注意: 通过 redirect 的响应类型也可以便捷的实现 redirectAction 的功能!
    <result name="index" type="redirectAction">
		<param name="actionName">testAction</param>
		<param name="namespace">/atguigu</param>
	</result>
	OR
	<result name="index" type="redirect">/atguigu/testAction.do</result>
    > chain: 转发到一个 Action
    	注意: 不能通过 type=dispatcher 的方式转发到一个 Action
         只能是:
    <result name="test" type="chain">
		<param name="actionName">testAction</param>
		<param name="namespace">/atguigu</param>
	</result>
	不能是:
	<result name="test">/atguigu/testAction.do</result>

TestAction.java

package com.atguigu.struts2.action;

/**
 * @Author :
 * @Date :Created in 2023/3/30 13:36
 * @Description:
 */
public class TestAction {

    public String execute() {
        System.out.println("TestAction's execute。。。。");
        return "success";
    }

}

TestDynamicMethodInvocationAction.java

package com.atguigu.struts2.action;

/**
 * @Author :
 * @Date :Created in 2023/3/31 9:21
 * @Description:
 */
public class TestDynamicMethodInvocationAction {

    public String save() {
        System.out.println("save....");
        return "success";
    }

    public String update() {
        System.out.println("update....");
        return "success";
    }

}

TestResultAction.java

package com.atguigu.struts2.action;

/**
 * @Author :
 * @Date :Created in 2023/3/30 9:22
 * @Description:
 */
public class TestResultAction {

    private int number;

    public void setNumber(int number) {
        this.number = number;
    }

    public String execute(){

        String result = null;

        //根据请求参数 number 的值, 返回对应的 JSP 页面
        //1. 若 number 是 3 个整数, 返回 success.jsp 页面
        if(number % 4 == 0)
            result = "success";

            //2. 若 number 除以 3 余 1, 返回 login.jsp
        else if(number % 4 == 1)
            result = "login";

            //3. 若 number 除以 3 余 2, 返回 index.jsp
        else if(number % 4 == 2)
            result = "index";

        else
            return "test";

        return result;
    }
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<!--打开允许动态方法调用的开关,默认是false-->
	<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

	<package name="default" namespace="/" extends="struts-default">

		<action name="testResult"
			    class="com.atguigu.struts2.action.TestResultAction"
				method="execute">
			<result name="success" type="dispatcher">/success.jsp</result>
			<result name="login" type="redirect">/login.jsp</result>
			<!--重定向到一个Action-->
<!--			<result name="index" type="redirectAction">-->
<!--				<param name="actionName">testAction</param>-->
<!--				<param name="namespace">/aiguigu</param>-->
<!--			</result>-->
			<!--通过 redirect 的响应类型也可以便捷的实现 redirectAction 的功能!-->
			<result name="index" type="redirect">/atguigu/testAction.do</result>
			<!--转发到一个 Action-->
			<result name="test" type="chain">
				<param name="actionName">testAction</param>
				<param name="namespace">/atguigu</param>
			</result>
		</action>

		<action name="testDynamicMethodInvocationAction"
				class="com.atguigu.struts2.action.TestDynamicMethodInvocationAction"
				method="save">
			<result>/success.jsp</result>
		</action>
	</package>

	<package name="testPackage" namespace="/aiguigu"  extends="struts-default">
		<action name="testAction" class="com.atguigu.struts2.action.TestAction">
			<result>/success.jsp</result>
		</action>
	</package>

</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-2</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

index.jsp

<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<br><br>
	<a href="testResult.do?number=4">Test Result</a>
	<br><br>
	<!--testDynamicMethodInvocationAction!update.do调用的就是update方法-->
	<a href="testDynamicMethodInvocationAction.do">Test DynamicMethodInvocation</a>
	<br><br>


</body>
</html>

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<h4>Success Page</h4>
	
</body>
</html>

第六章 通配符映射

6.1 通配符映射介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.2 代码总结

在这里插入图片描述

UserAction.java

package com.atguigu.struts2.helloword;

/**
 * @Author :
 * @Date :Created in 2023/3/30 18:43
 * @Description:
 */
public class UserAction {

    public String save(){
        System.out.println("save");
        return "save-success";
    }

    public String update(){
        System.out.println("update");
        return "update-success";
    }

    public String delete(){
        System.out.println("delete");
        return "delete-success";
    }

    public String query(){
        System.out.println("query");
        return "query-success";
    }

    public String test(){
        System.out.println("test");
        return "query-success";
    }

}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<package name="default" namespace="/" extends="struts-default">
		<action name="UserAction-save"
				class="com.atguigu.struts2.helloword.UserAction"
				method="test">
			<result name="query-success">/success.jsp</result>
		</action>
		<action name="UserAction-*"
				class="com.atguigu.struts2.helloword.UserAction"
				method="{1}">
			<result name="{1}-success">/success.jsp</result>
		</action>
		<action name="*-update"
				class="com.atguigu.struts2.helloword.UserAction"
				method="test">
			<result name="query-success">/success.jsp</result>
		</action>

	</package>



</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-4</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<a href="UserAction-save.do">User Save</a>
	<br><br>

	<a href="UserAction-update.do">User Update</a>
	<br><br>

	<a href="UserAction-delete.do">User Delete</a>
	<br><br>

	<a href="UserAction-query.do">User Query</a>
	<br><br>
</body>
</html>

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<h4>Success Page</h4>
	
</body>
</html>

第七章 OGNL

7.1 前言

在这里插入图片描述

7.2 值栈

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.3 OGNL

在这里插入图片描述

7.4 property标签

在这里插入图片描述

7.5 读取ObjectStack里的对象的属性

在这里插入图片描述
在这里插入图片描述

7.6 读取ContextMap里的对象的属性

在这里插入图片描述

7.7 调用字段和方法

在这里插入图片描述

7.8 访问数组类型的属性

在这里插入图片描述

7.9 访问List类型的属性

在这里插入图片描述

7.10 访问Map类型的属性

在这里插入图片描述

7.11 使用EL访问值栈中对象的属性

在这里插入图片描述

7.12 异常处理:exception-mapping元素

在这里插入图片描述

7.13 代码总结

在这里插入图片描述

note.txt

1. 关于值栈:

1). helloWorld 时, ${productName} 读取 productName 值, 实际上该属性并不在 request 等域对象中, 而是从值栈中获取的. 

2). ValueStack: 

I.  可以从 ActionContext 中获取值栈对象
II. 值栈分为两个逻辑部分

	> Map 栈: 实际上是 OgnlContext 类型, 是个 Map, 也是对 ActionContext 的一个引用. 里边保存着各种 Map:
	         requestMap, sessionMap, applicationMap, parametersMap, attr
	         
	> 对象栈: 实际上是 CompoundRoot 类型, 是一个使用 ArrayList 定义的栈. 里边保存各种和当前 Action 实例相关的对象.
	                   是一个数据结构意义的栈.
	                   
 2. Struts2 利用 s:property 标签和 OGNL 表达式来读取值栈中的属性值
 
 1). 值栈中的属性值:
 
 	> 对于对象栈: 对象栈中某一个对象的属性值
 	
 	> Map 栈: request, session, application 的一个属性值 或 一个请求参数的值. 
 	
 2). 读取对象栈中对象的属性:
 
 	> 若想访问 Object Stack 里的某个对象的属性. 可以使用以下几种形式之一: 
		
	  object.propertyName ; object['propertyName'] ; object["propertyName"]	
		
	> ObjectStack 里的对象可以通过一个从零开始的下标来引用. ObjectStack 里的栈顶对象可以用 [0] 来引用, 
	     它下面的那个对象可以用 [1] 引用. 
	   
	  [0].message   
	     
	> [n] 的含义是从第 n 个开始搜索, 而不是只搜索第 n 个对象
	
	> 若从栈顶对象开始搜索, 则可以省略下标部分: message 
	
	> 结合 s:property 标签: <s:property value="[0].message" />  <s:property value="message" />
 
 3). 默认情况下, Action 对象会被 Struts2 自动的放到值栈的栈顶. 

Product.java

package com.atguigu.struts2.valuestack;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

import java.util.Map;

public class Product implements RequestAware, SessionAware {

	private Integer productId;
	private String productName;
	private String productDesc;

	private double productPrice;

	public Integer getProductId() {
		return productId;
	}

	public void setProductId(Integer productId) {
		this.productId = productId;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getProductDesc() {
		return productDesc;
	}

	public void setProductDesc(String productDesc) {
		this.productDesc = productDesc;
	}

	public double getProductPrice() {
		return productPrice;
	}

	public void setProductPrice(double productPrice) {
		this.productPrice = productPrice;
	}

	public Product() {
		System.out.println("Product's constructor...");
	}

	private Map<String,Object> sessionMap=null;

	private Map<String,Object> requestMap=null;

	@Override
	public void setRequest(Map<String, Object> map) {
		requestMap=map;
	}

	@Override
	public void setSession(Map<String, Object> map) {
		sessionMap=map;
	}

	@Override
	public String toString() {
		return "Product [productId=" + productId + ", productName="
				+ productName + ", productDesc=" + productDesc
				+ ", productPrice=" + productPrice + "]";
	}

	public String save(){
		System.out.println("save: " + this);

		//1. 获取值栈
		ValueStack valueStack = ActionContext.getContext().getValueStack();

		//2. 创建 Test 对象, 并为其属性赋值
		Test test = new Test();
		test.setProductDesc("AABBCCDD");
		test.setProductName("ABCD");

		//3. 把 Test 对象压入到值栈的栈顶!
		valueStack.push(test);

		sessionMap.put("product",this);
		requestMap.put("test",test);

		int i=10/0;

		return "success";
	}

}

Test.java

package com.atguigu.struts2.valuestack;

public class Test {

	private String productName;
	private String productDesc;

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getProductDesc() {
		return productDesc;
	}

	public void setProductDesc(String productDesc) {
		this.productDesc = productDesc;
	}

}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<!-- 打开静态方法调用的限制 -->
	<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

	<package name="default" namespace="/" extends="struts-default">
		
		<global-results>
			<result name="input">/input.jsp</result>
		</global-results>

		<global-exception-mappings>
			<exception-mapping exception="java.lang.ArithmeticException" result="input"></exception-mapping>
		</global-exception-mappings>

		<action name="product-save"
				class="com.atguigu.struts2.valuestack.Product"
				method="save">

			<exception-mapping exception="java.lang.ArithmeticException" result="input"></exception-mapping>
			<result name="input" >/input.jsp</result>

			<result>/details.jsp</result>

		</action>
	</package>



</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-4</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

details.jsp

<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<s:debug></s:debug>

	ProductName: ^<s:property value="[0].productName"/>
	<br><br>
	
	ProductDesc: <s:property value="[1].productDesc"/>
	<br><br>
	
	ProductPrice: ${productPrice }
	<br><br>
	
	ProductPrice: ^<s:property value="[0].productPrice"/>
	<br><br>
	
	ProductPrice: ^^<s:property value="productPrice"/>
	<br><br>

	productName1:${sessionScope.product.productName}
	<s:property value="#session.product.productName"/>
	<br><br>
	productName2:${requestScope.test.productName}
	<s:property value="#request.test.productName"/>
	<br><br>

	<!--使用OGNL调用public类的public类型的静态字段和静态方法-->
	<s:property value="@java.lang.Math@PI"/>
	<br><br>
	<s:property value="@java.lang.Math@cos(0)"/>

	<br><br>
	<br><br>
	<br><br>
	<!--调用对象栈的方法为一个属性赋值-->
	<s:property value="setProductName('atiguigu')"/>
	<br><br>
	<s:property value="productName"/>

	<br><br>
	<br><br>
	<!--调用数组对象的属性-->
	<%
		String[] names=new String[]{"aa","bb","cc","dd"};
		request.setAttribute("names",names);
	%>
	<br><br>
	length: <s:property value="#attr.names.length"/>
	<br><br>
	names[2]:<s:property value="#attr.names[2]"/>
	<br><br>
	<%
		Map<String,String> letters=new HashMap<>();
		request.setAttribute("letters",letters);

		letters.put("AA","a");
		letters.put("BB","b");
		letters.put("CC","c");
	%>
	<br><br>
	<!--使用OGNL访问Map-->
	<s:property value="#attr.letters.size"/>
	<br><br>
	AA:<s:property value="#attr.letters['AA']"/>
	<%=request%>
</body>
</html>

input.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<s:debug></s:debug>
<%--	<s:property value="exceptionStack"></s:property>--%>
	<br>
	<br>
	<s:property value="exception"></s:property>
	${exception}
	<br>
	<s:property value="exception.message"></s:property>
	${exception.message}
	<br>

	<form action="product-save.action" method="post">

		ProductName: <input type="text" name="productName"/>
		<br><br>

		ProductDesc: <input type="text" name="productDesc"/>
		<br><br>

		ProductPrice: <input type="text" name="productPrice" />
		<br><br>
		
		<input type="submit" value="Submit"/>
		<br><br>
	
	</form>

</body>
</html>

第八章 通用标签

8.1 介绍

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.2 代码总结

在这里插入图片描述

note.txt

2.Struts2自动把Action对象放入到值栈中
1). 放入时间点为:Strut2终将调用Action类的Action方法,但在调用该方法之前:
   -》先创建一个StrutsActionProxy对象
   -》在创建StrutsActionProxy之后,对其进行初始化时,把Action对象放入了值栈中。

Person.java

package com.atguigu.struts2.valuestack;

/**
 * @Author :
 * @Date :Created in 2023/4/6 19:30
 * @Description:
 */
public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

PersonComparator.java

package com.atguigu.struts2.valuestack;

import java.util.Comparator;

/**
 * @Author :
 * @Date :Created in 2023/4/7 9:38
 * @Description:
 */
public class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getName().compareTo(o2.getName());
    }
}

Product.java

package com.atguigu.struts2.valuestack;

import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class Product implements RequestAware, SessionAware {

	private Integer productId;
	private String productName;
	private String productDesc;

	private double productPrice;

	public Integer getProductId() {
		return productId;
	}

	public void setProductId(Integer productId) {
		this.productId = productId;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getProductDesc() {
		return productDesc;
	}

	public void setProductDesc(String productDesc) {
		this.productDesc = productDesc;
	}

	public double getProductPrice() {
		return productPrice;
	}

	public void setProductPrice(double productPrice) {
		this.productPrice = productPrice;
	}

	public Product() {
		System.out.println("Product's constructor...");
	}

	private Map<String,Object> sessionMap=null;

	private Map<String,Object> requestMap=null;

	@Override
	public void setRequest(Map<String, Object> map) {
		requestMap=map;
	}

	@Override
	public void setSession(Map<String, Object> map) {
		sessionMap=map;
	}

	@Override
	public String toString() {
		return "Product [productId=" + productId + ", productName="
				+ productName + ", productDesc=" + productDesc
				+ ", productPrice=" + productPrice + "]";
	}

	private List<Person> persons =new LinkedList<>();

	public List<Person> getPersons() {
		return persons;
	}

	public void setPersons(List<Person> persons) {
		this.persons = persons;
	}

	public String testTag() {
		this.productId=1003;
		this.productDesc="intel";
		this.productName="cpu";
		this.productPrice=100;

		persons.add(new Person("AAA",11));
		persons.add(new Person("BBB",22));
		persons.add(new Person("CCC",33));
		persons.add(new Person("DDD",44));
		persons.add(new Person("EEE",55));
		return "success";
	}
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<!-- 打开静态方法调用的限制 -->
	<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

	<package name="default" namespace="/" extends="struts-default">

		<action name="testTag"
				class="com.atguigu.struts2.valuestack.Product"
				method="testTag">
			<result>/common-tag.jsp</result>
		</action>
	</package>
	
</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-4</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

common-tag.jsp

<%@ page import="com.atguigu.struts2.valuestack.Person" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.LinkedList" %>
<%@ page import="com.atguigu.struts2.valuestack.PersonComparator" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <s:debug></s:debug>
    <br>
    s:property:打印值栈中的属性值:对于对象栈,打印值栈中对应的属性值
    <br><br>
    <s:property value="productName"/>
    <br><br>
    对于Map栈,打印request,session,application的某个属性值或某个请求参数的值
    <br><br>
    <s:property value="#session.date"/>
    <br><br>
    <s:property value="#parameters.name[0]"/>
    <br><br>
    s:url:创建一个URL字符串的
    <br><br>
    <s:url value="/getProduct" var="url">
        <!--指定url包含的请求参数,1003不可能是一个属性名,struts2把1003直接作为属性值-->
        <s:param name="productId" value="1003"></s:param>
        <s:param name="date" value="#session.date"></s:param>
    </s:url>
    ${url}
    <br><br>
    <s:url value="/getProduct" var="url2">
        <!--对于value值会自动的进行OGNL解析!-->
        <s:param name="productId" value="productId"></s:param>
    </s:url>
    ${url2}
    <br><br>
    <s:url value="/getProduct" var="url3">
        <!--对于value值会自动的进行OGNL解析! 若不希望进行OGNL解析,则使用单引号引起来!-->
        <s:param name="productId" value="'fdfdfd'"></s:param>
    </s:url>
    ${url3}
    <br><br>
    <!--构建一个请求action的地址-->
    <s:url action="testAction" namespace="/helloworld" method="save" var="url4"></s:url>
    ${url4}
    <br><br>
    <s:url value="/testUrl" includeParams="get" var="url5"></s:url>
    ${url5}
    <br><br>
    <s:url value="/testUrl1" includeParams="all" var="url6"></s:url>
    ${url6}
    <br><br>
    <!--对于value值会自动的进行OGNL解析!-->
    <s:set name="productName" value="productName" scope="request"></s:set>
    productName:${requestScope.productName}
    <br><br>
    s:push:把一个对象在标签开始后压入到栈值中,标签结束时,弹出栈值
    <br><br>
    <%
        Person person=new Person();
        person.setName("123");
        person.setAge(10);
        request.setAttribute("person",person);
    %>
    <s:push value="#request.person">
        ${name}
    </s:push>
    <br><br>
    s:if,s:else,s:elseif:
    <br><br>
    <!--可以直接使用值栈中的属性-->
    <s:if test="productPrice>1000">
        17处理器
    </s:if>
    <s:elseif test="productPrice>800">
        15处理器
    </s:elseif>
    <s:else>
        13处理器
    </s:else>
    <br><br>
    <s:if test="#request.person.age>10">
        大于10
    </s:if>
    <s:else>
        小于或等于10
    </s:else>
    <br><br>
    s:iterator:遍历集合,对象里的每一个元素依次压入和弹出 ValueStack 栈
    <br><br>
    <%
        List<Person> personList=new LinkedList<>();
        personList.add(new Person("AA",10));
        personList.add(new Person("BB",20));
        personList.add(new Person("CC",30));
        personList.add(new Person("DD",40));
        personList.add(new Person("EE",50));
        request.setAttribute("personList",personList);
    %>
    <s:iterator value="#request.personList" status="status">
        index:${status.index}-count:${status.count}-${name}-${age}<br>
    </s:iterator>
    <br><br>
    <s:iterator value="persons">
        ${name}-${age}<br>
    </s:iterator>
    <br><br>
    s:sort可以对集合中的元素进行排序
    <br><br>
    <%
        PersonComparator pc=new PersonComparator();
        request.setAttribute("comparator",pc);
    %>
    <s:sort comparator="#request.comparator" source="persons" var="persons2"></s:sort>
    <s:iterator value="#attr.persons2">
        ${name}-${age}<br>
    </s:iterator>
    <br><br>
    s:date:对 Date 对象进行排版
    <br><br>
    <s:date name="#session.date" format="yyyy-MM-dd hh:mm:ss" var="date2"></s:date>
    s:date->${date2}
    <br><br>
    s:a
    <br><br>
    <!--可以使用%{}把属性包装起来,使其进行强制的OGNL解析-->
    <s:iterator value="persons">
        <s:a href="getPerson.action?name=%{name}">${name}</s:a>
    </s:iterator>
</body>
</html>

index.jsp

<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<a href="testTag.action?name=atguigu">testTag</a>
	<%
		session.setAttribute("date",new Date());
	%>
	<form action="testTag.action" method="post">
		<input type="text" name="username"/>
		<input type="submit" value="submit"/>
	</form>
</body>
</html>

第九章 表单标签

9.1 介绍

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

9.2 代码总结

在这里插入图片描述
City.java

package com.atguigu.struts2.valuestack;

/**
 * @Author :
 * @Date :Created in 2023/4/9 10:03
 * @Description:
 */
public class City {
    private Integer cityId;
    private String cityName;

    public Integer getCityId() {
        return cityId;
    }

    public void setCityId(Integer cityId) {
        this.cityId = cityId;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public City(Integer cityId, String cityName) {
        this.cityId = cityId;
        this.cityName = cityName;
    }

    public City() {
    }

    @Override
    public String toString() {
        return "City{" +
                "cityId=" + cityId +
                ", cityName='" + cityName + '\'' +
                '}';
    }
}

UerAction.java

package com.atguigu.struts2.valuestack;

import com.opensymphony.xwork2.ActionContext;

import java.util.List;

/**
 * @Author :
 * @Date :Created in 2023/4/8 15:41
 * @Description:
 */
public class UerAction {

    private String userId;
    private String userName;
    private String password;
    private String desc;
    private boolean married;
    private String gender;
    private List<String> city;
    private String age;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    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 getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public boolean isMarried() {
        return married;
    }

    public void setMarried(boolean married) {
        this.married = married;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public List<String> getCity() {
        return city;
    }

    public void setCity(List<String> city) {
        this.city = city;
    }

    public String getAge() {
        return age;
    }

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

    public String save() {
        System.out.println(this);
        UerAction ua=new UerAction();
        ua.setDesc("Oracle");
        ua.setPassword("121212");
        ua.setUserId("1001");
        ua.setUserName("AIAIAI");
        ActionContext.getContext().getValueStack().push(ua);
        return "input";
    }


    @Override
    public String toString() {
        return "UerAction{" +
                "userId='" + userId + '\'' +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", desc='" + desc + '\'' +
                ", married=" + married +
                ", gender='" + gender + '\'' +
                ", city=" + city +
                ", age='" + age + '\'' +
                '}';
    }
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<!-- 打开静态方法调用的限制 -->
	<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

	<package name="default" namespace="/" extends="struts-default">

		<action name="save"
				class="com.atguigu.struts2.valuestack.UerAction"
				method="save">
			<result name="input">/form-tag.jsp</result>
		</action>
	</package>
	
</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-4</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

form-tag.jsp

<%@ page import="com.atguigu.struts2.valuestack.City" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.LinkedList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <%
        List<City> cities=new LinkedList<>();
        cities.add(new City(1001,"AA"));
        cities.add(new City(1002,"BB"));
        cities.add(new City(1003,"CC"));
        cities.add(new City(1004,"DD"));
        request.setAttribute("cities",cities);
    %>
    <s:debug></s:debug>
    <br>
    <!--
        表单标签:
            1.使用和html的form标签的感觉差不多
            2.Struts2的form标签会生成一个table,以进行自动的排版
            3.可以对表单提交的值进行回显:从栈顶对象开始匹配属性,并把匹配的属性值赋到对应的标签的value中,若栈顶对象没有对应的属性,
                则依次向下找相对应的属性
    -->
    <s:form action="save">
        <s:hidden name="userId"></s:hidden>
        <s:textfield name="userName" label="UserName"></s:textfield>
        <s:password name="password" label="Password"></s:password>
        <s:textarea name="desc" label="Desc"></s:textarea>
        <s:checkbox name="married" label="Married"></s:checkbox>

        <s:radio name="gender" list="#{'1':'Male','0':'Female' }" label="Gender"></s:radio>

        <!--
            服务端需要使用集合类型,以保证能够被正常的回显!
        -->
        <s:checkboxlist name="city" list="#request.cities" listKey="cityId" listValue="cityName" label="City"></s:checkboxlist>

        <s:select list="{11,12,13,14,15,16,17,18,19,20}" headerKey="" headerValue="请选择" name="age" label="Age">
            <!--
                s:optgroup 可以用作s:select的子标签,用于显示更多的下拉框
                注意:必须有键值对,而不能使用一个集合,让其值既作为键,又做为值
            -->
            <s:optgroup label="21-30" list="#{21:21,222:333}"></s:optgroup>
            <s:optgroup label="31-40" list="#{31:32}"></s:optgroup>
        </s:select>

        <s:submit></s:submit>
    </s:form>

</body>
</html>

index.jsp

<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<a href="testTag.action?name=atguigu">testTag</a>
	<%
		session.setAttribute("date",new Date());
	%>
	<form action="testTag.action" method="post">
		<input type="text" name="username"/>
		<input type="submit" value="submit"/>
	</form>
</body>
</html>

第十章 代码练习

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Dao.java

package com.atguigu.struts2.valuestack.app;

import java.util.LinkedList;
import java.util.List;

/**
 * @Author :
 * @Date :Created in 2023/4/10 9:39
 * @Description:
 */
public class Dao {

    public List<Department> getDepartments() {

        List<Department> depts=new LinkedList<>();
        depts.add(new Department(1001,"AAA"));
        depts.add(new Department(1002,"BBB"));
        depts.add(new Department(1003,"CCC"));
        depts.add(new Department(1004,"DDD"));
        depts.add(new Department(1005,"EEE"));
        return depts;
    }

    public List<Role> getRoles() {
        List<Role> roles=new LinkedList<>();
        roles.add(new Role(2001,"XXX"));
        roles.add(new Role(2002,"YYY"));
        roles.add(new Role(2003,"ZZZ"));
        return roles;
    }

}

Department.java

package com.atguigu.struts2.valuestack.app;

/**
 * @Author :
 * @Date :Created in 2023/4/10 9:37
 * @Description:
 */
public class Department {

    private Integer deptId;

    private String deptName;

    public Integer getDeptId() {
        return deptId;
    }

    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    @Override
    public String toString() {
        return "Department{" +
                "deptId='" + deptId + '\'' +
                ", deptName='" + deptName + '\'' +
                '}';
    }

    public Department() {
    }

    public Department(Integer deptId, String deptName) {
        this.deptId = deptId;
        this.deptName = deptName;
    }
}

Employee.java

package com.atguigu.struts2.valuestack.app;

import org.apache.struts2.interceptor.RequestAware;

import java.util.List;
import java.util.Map;

/**
 * @Author :
 * @Date :Created in 2023/4/10 9:44
 * @Description:
 */
public class Employee implements RequestAware {

    private Map<String,Object> requestMap=null;

    private Dao dao=new Dao();

    @Override
    public void setRequest(Map<String, Object> map) {
        this.requestMap=map;
    }

    public String input() {
        requestMap.put("depts",dao.getDepartments());
        requestMap.put("roles",dao.getRoles());
        return "input";
    }

    private String name;
    private String password;
    private String gender;
    private String dept;
    private List<String> roles;
    private String desc;


    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getDept() {
        return dept;
    }

    public void setDept(String dept) {
        this.dept = dept;
    }

    public List<String> getRoles() {
        return roles;
    }

    public void setRoles(List<String> roles) {
        this.roles = roles;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String save() {

        return save();
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", gender='" + gender + '\'' +
                ", dept='" + dept + '\'' +
                ", roles=" + roles +
                ", desc='" + desc + '\'' +
                '}';
    }
}

Role.java

package com.atguigu.struts2.valuestack.app;

/**
 * @Author :
 * @Date :Created in 2023/4/10 9:36
 * @Description:
 */
public class Role {

    private Integer roleId;

    private String roleName;

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    @Override
    public String toString() {
        return "Role{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                '}';
    }

    public Role() {
    }

    public Role(Integer roleId, String roleName) {
        this.roleId = roleId;
        this.roleName = roleName;
    }
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<!-- 打开静态方法调用的限制 -->
	<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

	<package name="default" namespace="/" extends="struts-default">

		<action name="emp-*"
				class="com.atguigu.struts2.valuestack.app.Employee"
				method="{1}">
			<result name="{1}">/emp-{1}.jsp</result>
		</action>
	</package>

</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-4</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

emp-input.jsp

<%--
  Created by IntelliJ IDEA.
  User: 
  Date: 2023/4/10
  Time: 9:58
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <s:form action="emp-save">
        <s:textfield name="name" label="Name"></s:textfield>
        <s:password name="password" label="Password"></s:password>
        <s:radio name="gender" label="Gender" list="#{'1':'Male','0':'Female'}"></s:radio>
        <s:select name="dept" label="Department" list="#request.depts" listKey="deptId" listValue="deptName"></s:select>
        <s:checkboxlist name="roles" label="Role" list="#request.roles" listKey="roleId" listValue="roleName"></s:checkboxlist>
        <s:textarea name="desc" label="Desc"></s:textarea>
        <s:submit></s:submit>
    </s:form>
</body>
</html>

emp-save.jsp

<%--
  Created by IntelliJ IDEA.
  User: 
  Date: 2023/4/10
  Time: 13:32
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  Name:${name}
  <br><br>
  Password:${password}
  <br><br>
  Gender:${gender}
  <br><br>
  Dept:${dept}
  <br><br>
  Roles:${roles}
  <br><br>
  Desc:${desc}
  <br><br>
</body>
</html>

index.jsp

<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<a href="emp-input.action">Emp Input Page</a>
</body>
</html>

第十一章 主题

在这里插入图片描述

在这里插入图片描述

<s:form action="save" theme="simple"></s:form>
<s:textfield name="userName" label="UserName" theme="simple"></s:textfield>
request.setAttribute("theme","simple");
<constant name="struts.ui.theme" value="simple"></constant>

第十二章 ModelDriven和Preparable拦截器

12.1 准备工作

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

12.2 Params拦截器

在这里插入图片描述

在这里插入图片描述

12.3 把Action和Model隔开

在这里插入图片描述
在这里插入图片描述

12.4 ModelDriven拦截器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

12.5 Preparable拦截器

在这里插入图片描述

12.6 PrepareInterceptor拦截器

在这里插入图片描述

12.7 使用paramsPrepareParamsStack拦截器栈

在这里插入图片描述
在这里插入图片描述

12.8 代码总结

在这里插入图片描述

note.txt

1. Action 实现 ModelDriven 接口后的运行流程
1). 先会执行 ModelDrivenInterceptor 的 intercept 方法.
    public String intercept(ActionInvocation invocation) throws Exception {
    	//获取 Action 对象: EmployeeAction 对象, 此时该 Action 已经实现了 ModelDriven 接口
    	//public class EmployeeAction implements RequestAware, ModelDriven<Employee>
        Object action = invocation.getAction();
		//判断 action 是否是 ModelDriven 的实例
        if (action instanceof ModelDriven) {
        	//强制转换为 ModelDriven 类型
            ModelDriven modelDriven = (ModelDriven) action;
            //获取值栈
            ValueStack stack = invocation.getStack();
            //调用 ModelDriven 接口的 getModel() 方法
            //即调用 EmployeeAction 的 getModel() 方法
            /*
            public Employee getModel() {
				employee = new Employee();
				return employee;
			}
            */
            Object model = modelDriven.getModel();
            if (model !=  null) {
            	//把 getModel() 方法的返回值压入到值栈的栈顶. 实际压入的是 EmployeeAction 的 employee 成员变量
            	stack.push(model);
            }
            if (refreshModelBeforeResult) {
                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
            }
        }
        return invocation.invoke();
    }
2). 执行 ParametersInterceptor 的 intercept 方法: 把请求参数的值赋给栈顶对象对应的属性. 若栈顶对象没有对应的属性, 则查询
值栈中下一个对象对应的属性...
3). 注意: getModel 方法不能提供以下实现. 的确会返回一个 Employee 对象到值栈的栈顶. 但当前 Action 
的 employee 成员变量却是 null.
public Employee getModel() {
	return new Employee();
}


2. 使用 paramsPrepareParamsStack 拦截器栈后的运行流程
1). paramsPrepareParamsStack 和 defaultStack 一样都是拦截器栈. 而 struts-default 包默认使用的是
defaultStack
2). 可以在 Struts 配置文件中通过以下方式修改使用的默认的拦截器栈
<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
3). paramsPrepareParamsStack 拦截器在于
params -> modelDriven -> params

所以可以先把请求参数赋给 Action 对应的属性, 再根据赋给 Action 的那个属性值决定压到值栈栈顶的对象, 最后再为栈顶对象的属性赋值.

对于 edit 操作而言:
I.   先为 EmployeeAction 的 employeeId 赋值
II.  根据 employeeId 从数据库中加载对应的对象, 并放入到值栈的栈顶
III. 再为栈顶对象的 employeeId 赋值(实际上此时 employeeId 属性值已经存在)
IV.  把栈顶对象的属性回显在表单中.

4). 关于回显: Struts2 表单标签会从值栈中获取对应的属性值进行回显.
5). 存在的问题:
getModel 方法
public Employee getModel() {
	if(employeeId == null)
		employee = new Employee();
	else
		employee = dao.get(employeeId);
	return employee;
}

I.   在执行删除的时候, employeeId 不为 null, 但 getModel 方法却从数据库加载了一个对象. 不该加载!
II.  指向查询全部信息时, 也 new Employee() 对象. 浪费!

6). 解决方案: 使用 PrepareInterceptor 和 Preparable 接口.
7). 关于 PrepareInterceptor
[分析后得到的结论]
若 Action 实现了 Preparable 接口, 则 Struts 将尝试执行 prepare[ActionMethodName] 方法,
若 prepare[ActionMethodName] 不存在, 则将尝试执行 prepareDo[ActionMethodName] 方法.
若都不存在, 就都不执行.

若 PrepareInterceptor  的 alwaysInvokePrepare 属性为 false,
则 Struts2 将不会调用实现了 Preparable 接口的  Action 的 prepare() 方法

[能解决 5) 的问题的方案]

可以为每一个 ActionMethod 准备 prepare[ActionMethdName] 方法, 而抛弃掉原来的 prepare() 方法
将 PrepareInterceptor  的 alwaysInvokePrepare 属性置为 false, 以避免 Struts2 框架再调用 prepare() 方法.

如何在配置文件中为拦截器栈的属性赋值: 参看 /struts-2.3.15.3/docs/WW/docs/interceptors.html

<interceptors>
    <interceptor-stack name="parentStack">
        <interceptor-ref name="defaultStack">
            <param name="params.excludeParams">token</param>
        </interceptor-ref>
    </interceptor-stack>
</interceptors>

<default-interceptor-ref name="parentStack"/>

----------------------------------源代码解析---------------------------------

public String doIntercept(ActionInvocation invocation) throws Exception {
	//获取 Action 实例
    Object action = invocation.getAction();

	//判断 Action 是否实现了 Preparable 接口
    if (action instanceof Preparable) {
        try {
            String[] prefixes;
            //根据当前拦截器的 firstCallPrepareDo(默认为 false) 属性确定 prefixes
            if (firstCallPrepareDo) {
                prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
            } else {
                prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
            }
            //若为 false, 则 prefixes: prepare, prepareDo
            //调用前缀方法.
            PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
        }
        catch (InvocationTargetException e) {

            Throwable cause = e.getCause();
            if (cause instanceof Exception) {
                throw (Exception) cause;
            } else if(cause instanceof Error) {
                throw (Error) cause;
            } else {
                throw e;
            }
        }

		//根据当前拦截器的 alwaysInvokePrepare(默认是 true) 决定是否调用 Action 的 prepare 方法
        if (alwaysInvokePrepare) {
            ((Preparable) action).prepare();
        }
    }

    return invocation.invoke();
}

PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes) 方法:

public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
	//获取 Action 实例
	Object action = actionInvocation.getAction();
	//获取要调用的 Action 方法的名字(update)
	String methodName = actionInvocation.getProxy().getMethod();

	if (methodName == null) {
		// if null returns (possible according to the docs), use the default execute
        methodName = DEFAULT_INVOCATION_METHODNAME;
	}

	//获取前缀方法
	Method method = getPrefixedMethod(prefixes, methodName, action);

	//若方法不为 null, 则通过反射调用前缀方法
	if (method != null) {
		method.invoke(action, new Object[0]);
	}
}

PrefixMethodInvocationUtil.getPrefixedMethod 方法:

public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
	assert(prefixes != null);
	//把方法的首字母变为大写
	String capitalizedMethodName = capitalizeMethodName(methodName);

    //遍历前缀数组
    for (String prefixe : prefixes) {
        //通过拼接的方式, 得到前缀方法名: 第一次 prepareUpdate, 第二次 prepareDoUpdate
        String prefixedMethodName = prefixe + capitalizedMethodName;
        try {
        	//利用反射获从 action 中获取对应的方法, 若有直接返回. 并结束循环.
            return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
        }
        catch (NoSuchMethodException e) {
            // hmm -- OK, try next prefix
            if (LOG.isDebugEnabled()) {
                LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString());
            }
        }
    }
	return null;
}

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<a href="emp-list">List All Employees</a>
	
</body>
</html>

emp-list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<s:form action="emp-save" method="GET">
		
		<s:textfield name="firstName" label="FirstName"></s:textfield>
		<s:textfield name="lastName" label="LastName"></s:textfield>
		<s:textfield name="email" label="Email"></s:textfield>
		
		<s:submit></s:submit>		
	</s:form>

	<br>
	<hr>
	<br>
	
	<table cellpadding="10" cellspacing="0" border="1">
		<thead>
			<tr>
				<td>ID</td>
				<td>FirstName</td>
				<td>LastName</td>
				<td>Email</td>
				<td>Edit</td>
				<td>Delete</td>
			</tr>
		</thead>
		
		<tbody>
			<s:iterator value="#request.emps">
				<tr>
					<td>${employeeId }</td>
					<td>${firstName }</td>
					<td>${lastName }</td>
					<td>${email }</td>
					<td><a href="emp-edit?employeeId=${employeeId }">Edit</a></td>
					<td><a href="emp-delete?employeeId=${employeeId }">Delete</a></td>
				</tr>
			</s:iterator>
		</tbody>
		
	</table>

</body>
</html>

<%
	System.out.println("now: " + new java.util.Date());
%>

emp-edit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<s:debug></s:debug>
	
	<br>
	<br>
	
	<s:form action="emp-update.action" method="GET">
		
		<s:hidden name="employeeId"></s:hidden>
		
		<s:textfield name="firstName" label="FirstName"></s:textfield>
		<s:textfield name="lastName" label="LastName"></s:textfield>
		<s:textfield name="email" label="Email"></s:textfield>
		
		<s:submit></s:submit>		
	</s:form>
	
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-7</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>
	<constant name="struts.devMode" value="true"></constant>

	<package name="default" namespace="/" extends="struts-default">

		<!-- 修改 PrepareInterceptor 拦截器的 alwaysInvokePrepare 属性值为 false -->
		<interceptors>
			<interceptor-stack name="atguigustack">
				<interceptor-ref name="paramsPrepareParamsStack">
					<param name="prepare.alwaysInvokePrepare">false</param>
				</interceptor-ref>
			</interceptor-stack>
		</interceptors>

		<!--配置使用paramsPrepareParamsStack作为默认的拦截器栈-->
<!--		<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>-->
		<default-interceptor-ref name="atguigustack"></default-interceptor-ref>

		<action name="emp-*"
				class="com.atguigu.struts2.app.EmployeeAction"
				method="{1}">
			<result name="{1}">/emp-{1}.jsp</result>
			<result name="success" type="redirectAction">emp-list</result>
		</action>
	</package>
</struts>

Dao.java

package com.atguigu.struts2.app;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class Dao {
	
	private static Map<Integer, Employee> emps = new LinkedHashMap<Integer, Employee>();
	
	static{
		emps.put(1001, new Employee(1001, "AA", "aa", "aa@atguigu.com"));
		emps.put(1002, new Employee(1002, "BB", "bb", "bb@atguigu.com"));
		emps.put(1003, new Employee(1003, "CC", "cc", "cc@atguigu.com"));
		emps.put(1004, new Employee(1004, "DD", "dd", "dd@atguigu.com"));
		emps.put(1005, new Employee(1005, "EE", "ee", "ee@atguigu.com"));
	}
	
	public List<Employee> getEmployees(){
		return new ArrayList<>(emps.values());
	}
	
	public void delete(Integer empId){
		emps.remove(empId);
	}
	
	public void save(Employee emp){
		long time = System.currentTimeMillis();
		emp.setEmployeeId((int)time);
		
		emps.put(emp.getEmployeeId(), emp);
	}
	
	public Employee get(Integer empId){
		return emps.get(empId);
	}
	
	public void update(Employee emp){
		emps.put(emp.getEmployeeId(), emp);
	}
	
}

Employee.java

package com.atguigu.struts2.app;

public class Employee {

	private Integer employeeId;
	private String firstName;
	private String lastName;

	private String email;

	public Integer getEmployeeId() {
		return employeeId;
	}

	public void setEmployeeId(Integer employeeId) {
		this.employeeId = employeeId;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Employee(Integer employeeId, String firstName, String lastName,
			String email) {
		super();
		this.employeeId = employeeId;
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = email;
	}

	public Employee() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public String toString() {
		return "Employee [employeeId=" + employeeId + ", firstName="
				+ firstName + ", lastName=" + lastName + ", email=" + email
				+ "]";
	}
	
	

}

EmployeeAction.java

package com.atguigu.struts2.app;

import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import org.apache.struts2.interceptor.RequestAware;

import java.util.Map;

public class EmployeeAction implements RequestAware, ModelDriven<Employee>, Preparable {

	private Dao dao = new Dao();

	private Employee employee;

	//需要再当前的EmployeeAction中定义employeeId属性 以接收请求参数
	private Integer employeeId;

	private Map<String, Object> request;

	public void setEmployeeId(Integer employeeId) {
		this.employeeId = employeeId;
	}

	public Integer getEmployeeId() {
		return employeeId;
	}

	@Override
	public void setRequest(Map<String, Object> arg0) {
		this.request = arg0;
	}

	public String update(){
		dao.update(employee);
		return "success";
	}

	public void prepareUpdate() {
		employee=new Employee();
	}

	public String edit(){
		//1. 获取传入的employeeId:employee.getEmployeeId()

		//2. 根据employeeId获取Employee对象
		//Employee emp = dao.get(employee.getEmployeeId());

		//3. 把栈顶对象的属性装配好:此时栈顶对象是employee
		//目前employee对象只有employeeId属性,其他属性为null
        /*
			Struts2表单回显时:从值栈栈顶开始查找匹配的属性,若找到就添加套value属性中
		 */
//		employee.setEmail(emp.getEmail());
//		employee.setFirstName(emp.getFirstName());
//		employee.setLastName(emp.getLastName());

		//不能够进行表单的回显,因为经过重写赋值的employee对象已经不再是栈顶对象了
//		employee=dao.get(employee.getEmployeeId());

		//手动的把从数据库中获取的Employee对象放到值栈的栈顶
		//但此时值栈栈顶及第二个对象均为Employee对象,不够完美
//		ActionContext.getContext().getValueStack().push(dao.get(employee.getEmployeeId()));
		return "edit";
	}

	public void prepareEdit() {
		employee=dao.get(employeeId);
	}

	public String save(){
		dao.save(employee);
		return "success";
	}

	public void prepareSave() {
		employee=new Employee();
	}

	public String delete(){
		dao.delete(employeeId);
        /*
			返回结果类型应为:redirectAction
			也可以是chain:实际上chain是没有必要的,因为不需要再下一个Action中保留当前Action的状态
			还有,若使用chain,则达到目标页面后,地址栏显示的依然是删除的那个链接,刷新时会有重复提交
		 */
		return "success";
	}

	public String list(){
		request.put("emps", dao.getEmployees());
		return "list";
	}

	@Override
	public Employee getModel() {
        /*
			判断是Create还是Edit
			如果为Create,则employee = new Employee();
			如果为Edit,则employee=dao.get(employee.getEmployeeId());
			判断标准是否有employeeId这个请求参数,若有该参数,则视为Edit;若没有改参数,则视为Create
			若通过employeeId来判断,则需要再modelDriven拦截器之前先执行一个params拦截器!
			而这个可以通过使用paramsPrepareParams拦截器栈实现
			需要再struts.xml文件中配置使用paramsPrepareParams作为默认的拦截器栈
		 */
//		if (employeeId==null) {
//			employee = new Employee();
//		}else{
//			employee=dao.get(employeeId);
//		}
		return employee;
	}

	/**
	 * prepare方法的主要作用:为getModel()方法准备model的
	 * @throws Exception
	 */
	@Override
	public void prepare() throws Exception {
//		if (employeeId==null) {
//			employee = new Employee();
//		}else{
//			employee=dao.get(employeeId);
//		}
		System.out.println("prepare.....");
	}
}

第十三章 类型转换

13.1 内容提要

在这里插入图片描述

13.2 介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

13.3 代码总结

在这里插入图片描述

note.txt

问题1: 如何覆盖默认的错误消息?
1). 在对应的 Action 类所在的包中新建
    ActionClassName.properties 文件, ActionClassName 即为包含着输入字段的 Action 类的类名
2). 在属性文件中添加如下键值对: invalid.fieldvalue.fieldName=xxx


问题2: 如果是 simple 主题, 还会自动显示错误消息吗? 如果不会显示, 怎么办 ?
1). 通过 debug 标签, 可知若转换出错, 则在值栈的 Action(实现了 ValidationAware 接口) 对象中有一个  fieldErrors 属性.
该属性的类型为 Map<String, List<String>> 键: 字段(属性名), 值: 错误消息组成的 List. 所以可以使用 LE 或 OGNL 的方式
来显示错误消息: ${fieldErrors.age[0]}

2). 还可以使用 s:fielderror 标签来显示. 可以通过 fieldName 属性显示指定字段的错误.

问题3. 若是 simple 主题, 且使用  <s:fielderror fieldName="age"></s:fielderror> 来显示错误消息, 则该消息在一个
ul, li, span 中. 如何去除 ul, li, span 呢 ?
在 template.simple(WebContent\WEB-INF\lib\struts2-core-2.3.15.3.jar!\template\simple) 下面的 fielderror.ftl 定义了 simple 主题下, s:fielderror 标签显示错误消息的样式. 所以修改该
配置文件即可. 在 src 下新建  template.simple 包, 新建 fielderror.ftl 文件, 把原生的 fielderror.ftl 中的内容
复制到新建的 fielderror.ftl 中, 然后剔除 ul, li, span 部分即可.

问题4. 如何自定义类型转换器 ?
1). 为什么需要自定义的类型转换器 ? 因为 Struts 不能自动完成 字符串 到 引用类型 的 转换.
2). 如何定义类型转换器:
I.  开发类型转换器的类: 扩展 StrutsTypeConverter 类.
II. 配置类型转换器:
有两种方式
①. 基于字段的配置:
	> 在字段所在的 Model(可能是 Action, 可能是一个 JavaBean) 的包下, 新建一个 ModelClassName-conversion.properties 文件
	> 在该文件中输入键值对: fieldName=类型转换器的全类名.
	> 第一次使用该转换器时创建实例.
	> 类型转换器是单实例的!

②. 基于类型的配置:
	> 在 src 下新建 xwork-conversion.properties
	> 键入: 待转换的类型=类型转换器的全类名.
	> 在当前 Struts2 应用被加载时创建实例.

DateConverter.java

package com.atguigu.struts2.app.converters;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.util.StrutsTypeConverter;

import javax.servlet.ServletContext;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

public class DateConverter extends StrutsTypeConverter {

    private DateFormat dateFormat;

    public DateConverter() {
        System.out.println("DateConverter's constructor...");
    }

    public DateFormat getDateFormat(){
        if(dateFormat == null){
            //获取当前 WEB 应用的初始化参数 pattern
            ServletContext servletContext = ServletActionContext.getServletContext();
            System.out.println(servletContext);
            String pattern = servletContext.getInitParameter("pattern");
            dateFormat = new SimpleDateFormat(pattern);
        }

        return dateFormat;
    }

    /**
     * 页面请求到服务器端
     * @param context
     * @param values
     * @param toClass
     * @return
     */
    @Override
    public Object convertFromString(Map context, String[] values, Class toClass) {

        System.out.println("convertFromString...");

        if(toClass == Date.class){
            if(values != null && values.length > 0){
                String value = values[0];
                try {
                    return getDateFormat().parseObject(value);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }

        //若没有转换成功, 则返回 values
        return values;
    }

    /**
     * 页面回显
     * @param context
     * @param o
     * @return
     */
    @Override
    public String convertToString(Map context, Object o) {

        System.out.println("convertToString...");

        if(o instanceof Date){
            Date date = (Date) o;
            return getDateFormat().format(date);
        }

        //若转换失败返回 null
        return null;
    }

}

ConversionAction.java

package com.atguigu.struts2.app;

import com.atguigu.struts2.model.Customer;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class ConversionAction extends ActionSupport implements ModelDriven<Customer> {


	@Override
	public String execute() {
		System.out.println("model:"+model);
		return "success";
	}

	private Customer model;

	@Override
	public Customer getModel() {
		model=new Customer();
		return model;
	}
}

ConversionAction.properties

invalid.fieldvalue.age=错误的年龄格式.

ConversionAction-conversion.properties

birth=com.atguigu.struts2.app.converters.DateConverter

TestCollectionAction.java

package com.atguigu.struts2.app;

import com.atguigu.struts2.model.Manager;
import com.opensymphony.xwork2.ActionSupport;

import java.util.Collection;

public class TestCollectionAction extends ActionSupport {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private Collection<Manager> mgrs = null;
	
	public Collection<Manager> getMgrs() {
		return mgrs;
	}

	public void setMgrs(Collection<Manager> mgrs) {
		this.mgrs = mgrs;
	}

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

TestComplextPropertyAction.java

package com.atguigu.struts2.app;

import com.atguigu.struts2.model.Department;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class TestComplextPropertyAction extends ActionSupport 
	implements ModelDriven<Department>{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public String execute() throws Exception {
		System.out.println(department);
		return SUCCESS;
	}
	
	private Department department;

	@Override
	public Department getModel() {
		department = new Department();
		return department;
	}
	
}

Customer.java

package com.atguigu.struts2.model;

import java.util.Date;

/**
 * @Author :
 * @Date :Created in 2023/4/23 9:49
 * @Description:
 */
public class Customer {

    private int age;

    private Date birth;

    public int getAge() {
        return age;
    }

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

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "age=" + age +
                ", birth=" + birth +
                '}';
    }
}

Department.java

package com.atguigu.struts2.model;

/**
 * 1. Department 是模型, 实际录入的 Department. deptName 可以直接写到
 * s:textfield 的 name 属性中. 那 mgr 属性如何处理呢 ?
 * 
 * struts2 表单标签的 name 值可以被赋为 属性的属性: name=mgr.name, name=mgr.birth
 * 
 * 2. mgr 中有一个 Date 类型的 birth 属性, Struts2 可以完成自动的类型转换吗 ?
 * 
 * 全局的类型转换器可以正常工作!
 *
 */

public class Department {
	
	private Integer id;
	private String deptName;
	
	private Manager mgr;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getDeptName() {
		return deptName;
	}

	public void setDeptName(String deptName) {
		this.deptName = deptName;
	}

	public Manager getMgr() {
		return mgr;
	}

	public void setMgr(Manager mgr) {
		this.mgr = mgr;
	}

	@Override
	public String toString() {
		return "Department [id=" + id + ", deptName=" + deptName + ", mgr="
				+ mgr + "]";
	}
	
	
	
}

Manager.java

package com.atguigu.struts2.model;

import java.util.Date;

public class Manager {
	
	private String name;
	private Date birth;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Date getBirth() {
		return birth;
	}
	public void setBirth(Date birth) {
		this.birth = birth;
	}
	@Override
	public String toString() {
		return "Manager [name=" + name + ", birth=" + birth + "]";
	}
	
	
	
}

fielderror.ftl

<#--
/*
 * $Id: fielderror.ftl 927354 2010-03-25 11:41:30Z lukaszlenart $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
-->
<#if fieldErrors??><#t/>
    <#assign eKeys = fieldErrors.keySet()><#t/>
    <#assign eKeysSize = eKeys.size()><#t/>
    <#assign doneStartUlTag=false><#t/>
    <#assign doneEndUlTag=false><#t/>
    <#assign haveMatchedErrorField=false><#t/>
    <#if (fieldErrorFieldNames?size > 0) ><#t/>
        <#list fieldErrorFieldNames as fieldErrorFieldName><#t/>
            <#list eKeys as eKey><#t/>
                <#if (eKey = fieldErrorFieldName)><#t/>
                    <#assign haveMatchedErrorField=true><#t/>
                    <#assign eValue = fieldErrors[fieldErrorFieldName]><#t/>
                    <#if (haveMatchedErrorField && (!doneStartUlTag))><#t/>

                        <#assign doneStartUlTag=true><#t/>
                    </#if><#t/>
                    <#list eValue as eEachValue><#t/>
                     <#if parameters.escape>${eEachValue!?html}<#else>${eEachValue!}</#if>
                    </#list><#t/>
                </#if><#t/>
            </#list><#t/>
        </#list><#t/>
        <#if (haveMatchedErrorField && (!doneEndUlTag))><#t/>

            <#assign doneEndUlTag=true><#t/>
        </#if><#t/>
        <#else><#t/>
        <#if (eKeysSize > 0)><#t/>

            <#list eKeys as eKey><#t/>
                <#assign eValue = fieldErrors[eKey]><#t/>
                <#list eValue as eEachValue><#t/>
                    <#if parameters.escape>${eEachValue!?html}<#else>${eEachValue!}</#if>
                </#list><#t/>
            </#list><#t/>

        </#if><#t/>
    </#if><#t/>
</#if><#t/>

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<!-- 配置 Struts 可以受理的请求的扩展名 -->
	<constant name="struts.action.extension" value="action,do,"></constant>

	<package name="default" namespace="/" extends="struts-default">
		<action name="testConversion" class="com.atguigu.struts2.app.ConversionAction">
			<result>/success.jsp</result>
			<result name="input">/index.jsp</result>
		</action>
		<action name="testComplextProperty" class="com.atguigu.struts2.app.TestComplextPropertyAction">
			<result>/success.jsp</result>
		</action>
		<action name="testConversion2" class="com.atguigu.struts2.app.TestCollectionAction">
			<result>/success.jsp</result>
		</action>
	</package>
</struts>

xwork-conversion.properties

java.util.Date=com.atguigu.struts2.app.converters.DateConverter

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
  <display-name>struts2-7</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
    <!-- 配置 Struts2 的 Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <context-param>
        <param-name>pattern</param-name>
        <param-value>yyyy-MM-dd hh:mm:ss</param-value>
    </context-param>
</web-app>

complext-property.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<s:form action="testComplextProperty">
		
		<s:textfield name="deptName" label="DeptName"></s:textfield>
		
		<!-- 映射属性的属性 -->
		<s:textfield name="mgr.name" label="MgrName"></s:textfield>
		<s:textfield name="mgr.birth" label="MgrBirth"></s:textfield>
	
		<s:submit></s:submit>
	
	</s:form>
	
</body>
</html>

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<!--  
	问题1: 如何覆盖默认的错误消息?
	1). 在对应的 Action 类所在的包中新建  
	    ActionClassName.properties 文件, ActionClassName 即为包含着输入字段的 Action 类的类名
	2). 在属性文件中添加如下键值对: invalid.fieldvalue.fieldName=xxx
	
	
	问题2: 如果是 simple 主题, 还会自动显示错误消息吗? 如果不会显示, 怎么办 ?
	1). 通过 debug 标签, 可知若转换出错, 则在值栈的 Action(实现了 ValidationAware 接口) 对象中有一个  fieldErrors 属性.
	该属性的类型为 Map<String, List<String>> 键: 字段(属性名), 值: 错误消息组成的 List. 所以可以使用 LE 或 OGNL 的方式
	来显示错误消息: ${fieldErrors.age[0]}
	
	2). 还可以使用 s:fielderror 标签来显示. 可以通过 fieldName 属性显示指定字段的错误.
	
	问题3. 若是 simple 主题, 且使用  <s:fielderror fieldName="age"></s:fielderror> 来显示错误消息, 则该消息在一个 
	ul, li, span 中. 如何去除 ul, li, span 呢 ?
	在 template.simple(WebContent\WEB-INF\lib\struts2-core-2.3.15.3.jar!\template\simple) 下面的 fielderror.ftl 定义了 simple 主题下, s:fielderror 标签显示错误消息的样式. 所以修改该
	配置文件即可. 在 src 下新建  template.simple 包, 新建 fielderror.ftl 文件, 把原生的 fielderror.ftl 中的内容
	复制到新建的 fielderror.ftl 中, 然后剔除 ul, li, span 部分即可. 
	
	问题4. 如何自定义类型转换器 ?  
	1). 为什么需要自定义的类型转换器 ? 因为 Struts 不能自动完成 字符串 到 引用类型 的 转换.
	2). 如何定义类型转换器:
	I.  开发类型转换器的类: 扩展 StrutsTypeConverter 类.
	II. 配置类型转换器: 
	有两种方式
	①. 基于字段的配置: 
		> 在字段所在的 Model(可能是 Action, 可能是一个 JavaBean) 的包下, 新建一个 ModelClassName-conversion.properties 文件
		> 在该文件中输入键值对: fieldName=类型转换器的全类名. 
		> 第一次使用该转换器时创建实例. 
		> 类型转换器是单实例的!	
	
	②. 基于类型的配置:
		> 在 src 下新建 xwork-conversion.properties
		> 键入: 待转换的类型=类型转换器的全类名.
		> 在当前 Struts2 应用被加载时创建实例. 
		
	-->
	
	<s:debug></s:debug>
	
	<s:form action="testConversion" theme="simple">
		Age: <s:textfield name="age" label="Age"></s:textfield>
		${fieldErrors.age[0] }^
		<s:fielderror fieldName="age"></s:fielderror>
		<br><br>
		
		Birth: <s:textfield name="birth"></s:textfield>
		<s:fielderror fieldName="birth"></s:fielderror>
		<br><br>
		
		<s:submit></s:submit>
	</s:form>
	
</body>
</html>

manager-input.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="scripts/jquery-1.4.2.js"></script>
<script type="text/javascript">
	
	$(function(){
		
		var count = 0;
		
		$("#add").click(function(){
			count++;
			
			$("#button").before("<tr><td>Mgrs[" + count + "].Name:</td><td><input name='mgrs[" + count + "].name'/></td></tr>")
			            .before("<tr><td>Mgrs[" + count + "].Birth:</td><td><input name='mgrs[" + count + "].birth'/></td></tr>");
			
			return false;
		
		});
		
		$("#remove").click(function(){

			count--;
			
			$("#button").prev("tr").remove();
			$("#button").prev("tr").remove();
			
			return false;
		
		});
		
	});
	
</script>
</head>
<body>
	
	<form action="testConversion2.action">
	
		<table>
		
			<tbody>
				
				<tr>
					<td>Mgrs[0].Name:</td>
					<td><input name="mgrs[0].name"/></td>
				</tr>
				
				<tr>
					<td>Mgrs[0].Birth:</td>
					<td><input name="mgrs[0].birth"/></td>
				</tr>
				
				<tr id="button">
					<td><button id="add">新加一个</button></td>
					<td><button id="remove">删除一个</button></td>
				</tr>
				
				<tr>
					<td colspan="2" align="right">
						<input type="submit" value="Submit"/>
					</td>
				</tr>
			
			</tbody>
			
		</table>
		
	</form>
	
</body>
</html>

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h4>Success Page</h4>

</body>
</html>

Customer-conversion.properties

birth=com.atguigu.struts2.app.converters.DateConverter
posted @ 2023-05-02 23:59  KeepArlen  阅读(39)  评论(0)    收藏  举报