contextMap

Struts2的官方文档对contextMap的说明:
这里写图片描述
说明:
这里写图片描述

动作类的生命周期

明确:动作类是多例的,每次动作访问,动作类都会实例化。所以是线程安全的。与Struts1的区别是,struts1的动作类是单例的。

请求动作的数据存放

在每次动作执行前,核心控制器StrutsPrepareAndExecuteFilter都会创建一个ActionContext和ValueStack对象。且每次动作访问都会创建。
这两个对象存储了整个动作访问期间用到的数据。并且把数据绑定到了线程局部变量(ThreadLocal)上了。所以是线程安全的。
个人理解:ContextMap是绑定到了线程上面了,成为了局部变量,上图中他包含的对象的引用就是httpServletRequet,Seesion等。这个里面的session,request,application等都各自只有一份,我们可以通过各种不同的方式拿到对象的引用

contextMap:存储数据

contextMap是有两个部分组成的,一个是ActionContext,它是一个map;一个是valueStack,它是一个栈。这两部分就是用来存取数据用的

1、利用ActionContext存数据;
ActionContext的获取需要调用getContext()从当前线程中获取

import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

/**
 * 数据的方式
 */
public class Demo1Action extends ActionSupport {
    public String execute(){
        //1得到ActionContext对象,这个时候最大的map对象
        ActionContext context = ActionContext.getContext();
        //向其中添加数据
        context.put("contextMap", "hello,world!");
        System.out.println(context.hashCode());
        ActionContext context2 = ServletActionContext.getContext();
        System.out.println(context2.hashCode());

        //往session中存取数据
        //1.使用Actioncontext获取sessionMap
        Map<String, Object> sessionMap = context.getSession();
        sessionMap.put("name", "yanglin");
        //2.得到session对象来存取
        HttpSession session = ServletActionContext.getRequest().getSession();
        session.setAttribute("age",23);

        //往ServletContext域中存取数据
        //方式一:
        Map<String, Object> applicationMap = context.getApplication();
        applicationMap.put("domain", "my");
        //方式二:
        ServletContext servletContext = ServletActionContext.getServletContext();
        servletContext.setAttribute("way", "way");
        return SUCCESS;
    }
}

2、利用ValueStack存数据:
valuestack的获取方式有如下几种:

        获取ValueStack对象的引用
        //第一种方式:获取HttpServletRequest对象,通过对象的getAttribute方法,从域中取
        //1.获取request对象
        HttpServletRequest request = ServletActionContext.getRequest();
        //2.根据key获取ValueStack对象的引用
        ValueStack vs1 = (ValueStack)request.getAttribute("struts.valueStack");
        System.out.println(vs1.hashCode());

        //第二种方式:先获取ActionContext对象,再取出requestMap,然后通过map的get方法获取
        //1.获取ActionContext对象
        ActionContext context = ActionContext.getContext();
        //2.获取requestMap
        Map<String,Object> requestAttribute = (Map<String,Object>)context.get("request");
        //3.根据key获取对象的引用
        ValueStack vs2 = (ValueStack)requestAttribute.get("struts.valueStack");
        System.out.println(vs2.hashCode());


        //第三种方式:使用ActionContext对象的方法,直接获取ValueStack对象的引用
        ValueStack vs3 = context.getValueStack();
        System.out.println(vs3.hashCode());

ValueStack中有一个getRoot()方法:
这里写图片描述
CompoundRoot是一个具有栈功能的继承了arraylist的类
这里写图片描述

栈的操作:

valueStack.push(new Student("zeroyoung",23));
/**
* 栈的其他方法:
*  setValue(String expr, Object value);
*       String expr:它是一个OGNL表达式
*       Object value:我们要操作的数据
*  把数据存到哪里去?
*   看expr是否使用了#
*   如果使用了#,操作的就是ContextMap中
*   如果没使用#,操作的就是ValueStack
*/
valueStack.setValue("#names", "fuck");//把数据放到ContextMap中。 key是name  valeu=张三
valueStack.setValue("name", "张三");//把ValueStack中第一个name属性的值换成李四。如果没有一个name属性的对应的setName方法,会报错。

/*
*set(String key, Object o);
*  String key : Map的key
*  Object o : map的value
*  如果栈顶是一个Map元素,直接把key作为map的key,把Object作为map的value存入。执行的是替换的操作存入的是栈顶。
*  如果栈顶不是一个Map元素,创建一个Map对象,把key作为map的key,把Object作为map的value,压入栈顶。执行的是进栈的操作
 */
valueStack.set("s1", new Student("王五",18));
valueStack.push(new Student("test",23));
valueStack.set("s2", new Student("aaa",28));

3、取数据:用Struts2的标签(OGNL表达式)在JSP上用的最多
使用OGNL表达式来去,struts2的OGNL表达式必须写在struts2标签中。

<%@ taglib uri="/struts-tags" prefix="s" %>
  • 使用s:property取数据
    a、取contextMap中的数据,需使用#
<%-- 使用 s:property来获取ActionContext中的数据 
        value属性的取值是一个OGNL表达式--%>
    <br/>---------获取大Map中的数据-------------<br/>
    <s:property value="#contextMap"/>
    <hr/>
    <br/>---------获取小Map中的数据,session等中的数据-------------<br/>
    <%-- 以为小map在大map中,所有使用#大Map的key.小Map的key --%>
    <s:property value="#session.name" /><br/>
    <s:property value="#session.age" /><br/>
    <s:property value="#application.way" />

这里写图片描述
这里写图片描述

b、取contextMap里面ValueStack中对象的属性:直接写属性名
如果遇有对象属性重名,可以通过OGNL表达式,选择查找的起始位置

    <%--使用s:property标签,获取ValueStack中的元素。
        value属性的取值是一个OGNL表达式。它只能获取元素中的属性。
        注意:
            取ValueStack中的对象属性时,不使用#。
        它是从栈顶逐个对象查找指定的属性名称。只要找到了,就不再继续查找。
    --%>
    <s:property value="name"/><br/>
    <s:property value="s2.name"/><br/>
    <hr/>
    <%--s:property什么都不写:
        默认取栈顶元素
     --%>
    <s:property />

    <%--获取ValueStack中指定位置的属性 :
        使用的是[索引].属性名称。这个功能的实现是使用切片的方式,
        [2].name意思是去掉栈顶的两个元素之后然后再在valueStack的
        Property Name中一个一个往下寻找寻找key 
    --%>
   0-name <s:property value="[0].name" /><br/>
   1-name <s:property value="[1].name" /><br/>
   2-name <s:property value="[2].name" /><br/>
   3-name <s:property value="[3].name" /><br/>
   4-name <s:property value="[4].name" /><br/>

这里写图片描述
这里写图片描述

特殊说明:当s:property不给定value属性时,默认取栈顶对象。


OGNL的使用总结:
  • 根(valueStack)中对象的属性,不使用#
  • contextMapkey的值,要使用#
``` package main.java.com.example; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; import java.util.HashMap; import java.util.Map; @WebServlet("/exampleServlet") public class ExampleServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Map<String, String> requestMap = new HashMap<>(); requestMap.put("key1", "value1"); requestMap.put("key2", "value2"); request.setAttribute("requestMap", requestMap); Map<String, String> sessionMap = new HashMap<>(); sessionMap.put("key3", "value3"); sessionMap.put("key4", "value4"); request.getSession().setAttribute("sessionMap", sessionMap); Map<String, String> contextMap = new HashMap<>(); contextMap.put("key5", "value5"); contextMap.put("key6", "value6"); getServletContext().setAttribute("contextMap", contextMap); RequestDispatcher dispatcher = request.getRequestDispatcher("/example.jsp"); dispatcher.forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } <%@ page import="java.util.Map" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>EL Expression Example</title> </head> <body> <h2>Request Scope Map</h2> <ul> <c:forEach var="entry" items="${requestScope.requestMap}"> <li>${entry.key} : ${entry.value}</li> </c:forEach> </ul> <h2>Session Scope Map</h2> <ul> <c:forEach var="entry" items="${sessionScope.sessionMap}"> <li>${entry.key} : ${entry.value}</li> </c:forEach> </ul> <h2>ServletContext Scope Map</h2> <ul> <c:forEach var="entry" items="${applicationScope.contextMap}"> <li>${entry.key} : ${entry.value}</li> </c:forEach> </ul> </body> </html>```java代码为1-33行,jsp页面代码为34-64行,我通过IDEA运行tomcat9,使用java-web框架运行后,遍历map集合一直无法实现效果,请问代码有什么问题吗
03-21
{ "log.level": "debug", "@timestamp": "2025-09-29T10:05:21.342+0800", "log.logger": "processors", "log.origin": { "function": "github.com/elastic/beats/v7/libbeat/publisher/processing.debugPrintProcessor.func1", "file.name": "processing/processors.go", "file.line": 213 }, "message": "Publish event: {\n \"@timestamp\": \"2025-09-29T02:05:21.604Z\",\n \"@metadata\": {\n \"beat\": \"filebeat\",\n \"type\": \"_doc\",\n \"version\": \"9.1.1\"\n },\n \"kafka\": {\n \"offset\": 29850,\n \"key\": \"\",\n \"headers\": [],\n \"topic\": \"filebeat01\",\n \"partition\": 2\n },\n \"message\": \"{\r\n \\\"instant\\\" : {\r\n \\\"epochSecond\\\" : 1759111521,\r\n \\\"nanoOfSecond\\\" : 603311700\r\n },\r\n \\\"thread\\\" : \\\"http-nio-18082-exec-1\\\",\r\n \\\"level\\\" : \\\"INFO\\\",\r\n \\\"loggerName\\\" : \\\"com.ep.model.controller.ModelManageController\\\",\r\n \\\"message\\\" : \\\"---------------------------网络安全日志日志=================================\\\",\r\n \\\"endOfBatch\\\" : false,\r\n \\\"loggerFqcn\\\" : \\\"org.apache.logging.slf4j.Log4jLogger\\\",\r\n \\\"contextMap\\\" : {\r\n \\\"attackType\\\" : \\\"网络安全日志日志\\\",\r\n \\\"destinationIp\\\" : \\\"网络安全日志日志\\\",\r\n \\\"detectionTool\\\" : \\\"网络安全日志日志\\\",\r\n \\\"handlingResult\\\" : \\\"网络安全日志日志\\\",\r\n \\\"logType\\\" : \\\"security-event-logs\\\",\r\n \\\"message\\\" : \\\"网络安全日志日志\\\",\r\n \\\"sourceIp\\\" : \\\"127.0.0.1\\\",\r\n \\\"threatLevel\\\" : \\\"网络安全日志日志\\\",\r\n \\\"username\\\" : \\\"张三\\\"\r\n },\r\n \\\"threadId\\\" : 98,\r\n \\\"threadPriority\\\" : 5,\r\n \\\"timestamp\\\" : \\\"2025-09-29 10:05:21.603\\\"\r\n}\r\n\",\n \"input\": {\n \"type\": \"kafka\"\n },\n \"ecs\": {\n \"version\": \"8.0.0\"\n },\n \"host\": {\n \"name\": \"centos8\"\n },\n \"agent\": {\n \"ephemeral_id\": \"0a1780e0-8d42-4d71-a1c0-6baff229fc74\",\n \"id\": \"059145dc-1dbe-4fe8-9ffb-6fc085978059\",\n \"name\": \"centos8\",\n \"type\": \"filebeat\",\n \"version\": \"9.1.1\"\n }\n}", "service.name": "filebeat", "log.type": "event", "ecs.version": "1.6.0" }这是我根据日志获取的数据信息,\"logType\" : \"security-event-logs\",确实是我想要的值,但是依旧没有生成对应的索引
09-30
# ============================== Filebeat Inputs =============================== filebeat.inputs: - type: filestream id: my-filestream-id enabled: true paths: - /home/elastic/filebeat/test.log json: keys_under_root: true overwrite_keys: true - type: kafka enabled: true hosts: ["192.168.0.150:9092"] # 注意:Kafka默认端口是9092,若此处是笔误需修正为9092 topics: ["filebeat01"] group_id: "test-consumer-group1" version: 2.0.0 fields_under_root: true # ============================== Filebeat Modules ============================== filebeat.config.modules: path: ${path.config}/modules.d/*.yml reload.enabled: false # ============================== Setup =============================== setup.template.settings: index.number_of_shards: 1 setup.kibana: # 如需连接 Kibana,添加 host: "http://localhost:5601" # ============================== Processors =============================== processors: # 新增:解析message中的JSON字符串 - decode_json_fields: fields: ["message"] # 对message字段进行JSON解析 target: "" # 解析后的字段直接放到根级别(覆盖原有字段) overwrite_keys: true # 允许覆盖同名字段 ignore_missing: true # 若message不是JSON,不报错 # 1. 提取 contextMap 字段到根级别(关键:为 logType 添加 default 值) - copy_fields: fields: # 为 logType 设置默认值 "unknown"(源字段不存在/为空时生效) - from: contextMap.logType to: logType default: "unknown" # 核心修正:直接设置默认值,无需临时字段 # 其他字段按需添加 default(可选) - from: contextMap.account to: account default: "unknown" - from: contextMap.sessionId to: sessionId default: "unknown" - from: contextMap.sourceIp to: sourceIp default: "unknown" - from: contextMap.opType to: opType default: "unknown" - from: contextMap.opTargetType to: opTargetType default: "unknown" - from: contextMap.opTargetDetail to: opTargetDetail default: "unknown" ignore_missing: true # 源字段不存在时不报错 # 2. 解析 timestamp 为 @timestamp(保留) - timestamp: field: timestamp layouts: - '2006-01-02 15:04:05.000' test: - '2025-08-19 17:09:18.288' ignore_missing: true # 3. 按 logType 保留字段(保留,无 ignore_missing) - include_fields: fields: ["@timestamp", "timestamp", "logType", "account", "sessionId", "sourceIp", "opType", "opTargetType", "opTargetDetail", "message"] when: equals: logType: "account-operations-logs" - include_fields: fields: ["@timestamp", "timestamp", "logType", "username", "role", "sourceIp", "authType", "status", "failureReason", "message"] when: equals: logType: "login-logs" - include_fields: fields: ["@timestamp", "timestamp", "logType", "username", "currentRole", "previousRole", "currentSubstation", "previousSubstation", "sourceIp", "failureReason", "opUsername", "message"] when: equals: logType: "account-change-logs" - include_fields: fields: ["@timestamp", "timestamp", "logType", "username", "userRole", "opSite", "opType", "targetObject", "opResult", "failureReason", "sourceIp", "approvalUsername", "message"] when: equals: logType: "device-control-logs" - include_fields: fields: ["@timestamp", "timestamp", "logType", "deviceSource", "eventType", "message"] when: equals: logType: "system-logs" - include_fields: fields: ["@timestamp", "timestamp", "logType", "sourceIp", "destinationIp", "attackType", "detectionTool", "threatLevel", "username", "handlingResult", "message"] when: equals: logType: "security-event-logs" # 4. 清理冗余字段(保留) - drop_fields: fields: ["contextMap", "instant", "thread", "level", "loggerName", "endOfBatch", "loggerFqcn", "threadId", "threadPriority"] ignore_missing: true # ============================== Outputs =============================== output.elasticsearch: hosts: ["http://192.168.0.150:9200"] # path: "/tmp/filebeat-test" # 输出目录 # filename: "processed-data.log" indices: - index: "log-%{[logType]}-%{+yyyy.MM.dd}" when: regexp: logType: "account-operations-logs|login-logs|account-change-logs|device-control-logs|system-logs|security-event-logs" - index: "log-other-%{+yyyy.MM.dd}" preset: balanced # ============================== Logging =============================== logging.level: debug path.data: /home/elastic/filebeat-data path.logs: /home/elastic/filebeat-data/logs 解析一下这个配置信息
09-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值