如何将一个对象从前端传递到Struts 2

6
我正在尝试通过JavaScript将字段的值发送到Struts2后端,但它返回了NullpointerException
<input type="hidden" id="employee.payslip.id" name="employee.payslip.id" value="5"/>
....

一旦表单提交,请求将发送到以下JavaScript方法以发送到后端。
 function payslipPayment(){

     var formValues = $('#myform').serialize();
     ....
     xmlhttp.open("get","../payslip/pay?"+formValues,false);
     xmlhttp.send();

 }

请求将会被创建并按照以下方式发送

http://localhost/payslip/pay/employee.payslip.id=5&employee.payslip.year=2013&....

但是在后端,当我尝试显示该值时,它返回NullPointerException

Java:

public class payslip {

 private Employee employee;

 public String pay{
    System.out.println("Id:"+employee.payslip.id):
    System.out.println("Year:"+employee.payslip.year;
    ...
 }

 getter and setter 

}

类:

public class Employee {
   private Payslip payslip;
   ....
   getter and setter
}

public class Payslip{
  private long id;
  ...
  getter and setter
}

问题是在JS中序列化,而在Java中反序列化。因此,您应该考虑序列化是否正确传递到Java,并且在获取正确字符串后,Java是否正确地进行了反序列化。 - farmer1992
问题在于我不知道如何解决这个问题? - J888
1
你正在使用哪个框架来解析HTTP请求中的参数到Java类中? - leesei
1
http://localhost/payslip/pay/employee.payslip.id = 5 应该改为 http://localhost/payslip/pay/employee.payslip.id=5(无空格)吗? - leesei
1
显示的URL 'http://localhost/payslip/pay/' 没有 '?',但代码中有,所以应该没问题。我猜 'pay' 操作映射到 'payslip' 类和 'pay' 方法。另外,通过 employee.payslip.id,你实际上是指 employee.getPayslip().getId()。它们应该可以正常工作。你能否说一下 employee 引用本身是否为空或者 getPayslip() 是否返回空值? - Ravindra HV
显示剩余4条评论
8个回答

3

空指针异常意味着员工或工资单未初始化。如果您正在使用Struts2,则使用参数拦截器和模型驱动方法应该可以解决您的问题。


这正是我想说的。然而,目前的方法为什么不起作用并不清楚。 - Ravindra HV
@RavindraHV 伙计们,这是否意味着直接将请求发送到操作而不使用JavaScript?如果不是,你能给我一个例子吗? - J888
@J888 你仍需在服务器端触发该动作。你可以使用HTML表单或JavaScript-XHR,从服务器角度来看两者都可以。在模型驱动中,模型(Bean)是显式定义的(并针对每个请求实例化)。如果在操作中有任何不应通过请求设置的setter,则使用模型驱动,名称与字段相同的请求参数不会被意外分配。因此,这总是更安全的选择。 - Ravindra HV

2
  1. 为Employee和Payslip实现可序列化接口。同时,确保两者都有空构造函数。

  2. 启用struts2的devMode以获取额外的日志。启用后,您将看到OGNL异常,其中指定了出现问题的字段。该错误必须非常直观易处理。http://www.mkyong.com/struts2/struts-2-development-mode-example/

  3. 我猜这个操作使用的拦截器栈存在问题,只需尝试使用defaultStack。

<action name="payslip/pay" class="...">
    <interceptor-ref name="defaultStack"/>
    <result name="success">/success.jsp</result>
    <result name="input">/error.jsp</result>
</action>

2
在action标签中添加输入参数,这样可以让你从Struts action类向表单/.jsp传递参数。
struts.xml
<action name="..." class="UserAction">
 <param name="id"></param>
 <result name="input">/WEB-INF/jsp/User.jsp</result>
</action>

动作类

public class UserAction {
private int id;

// this is called by the struts.xml to set the value
public void setId(int id) {
this.id = id;
}

//a getter is needed as well to display value in the .jsp

}

既然它是一个隐藏的变量而不是值栈的一部分,您可以尝试通过这种方式传递它。

如果这不是您的问题; 我认为您必须将bean注入Action类中。将Employee bean注入到Action类中会有所帮助。

还要调试valuestack。


2
你可以像Alexey提出的那样做,或者你可以按照以下步骤操作。你可以使用ServletRequestAware和ServletResponseAware接口,然后使用request.getParameter()方法来获取传递的值。下面是如何执行此操作的示例。

Action类struts配置

<action name="hello" method="execute"
            class="com.home.struts2.HelloAction">
            <result name="success">hello.jsp</result> 
        </action>

动作类

 public class HelloAction extends ActionSupport implements ServletRequestAware,ServletResponseAware{
        HttpServletResponse response;
        HttpServletRequest request;

        public String execute() {

             System.out.println("AjaxCall" + request.getParameter("param"));
              String infoXml = "Parameter passed: " + request.getParameter("param");
              response.setContentType("text/html");
                response.setHeader("Cache-Control", "no-cache");
                try {
                    response.getWriter().write(infoXml);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }

                return null;

        }

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

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

        public HttpServletRequest getServletRequest() {
            return this.request;
        }

    }

JavaScript
var xmlHttp;
function sendreq(){  

        var URL = "hello.action?param=sandy";
        try{
            xmlHttp=new XMLHttpRequest();
        }catch (e){
            try{
                xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
            }catch (e){
                try{
                    xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
                }catch (e){
                    alert("Your browser does not support AJAX!");
                    return false;
                }
            }
        }

        xmlHttp.onreadystatechange = showMessage;

        xmlHttp.open("GET", URL, true);

        xmlHttp.send(null);
    }

谢谢,如果传递了10个不同的值,这是否有效? - J888
你所需要做的就是在get请求中正确地传递它,并使用request.getParameter()检索它。 - karthick
JS: 变量 URL = "hello.action?param=sandy&param2=xxx";Java: request.getParameter('param2') - karthick
那么在这种情况下,我需要拥有10个这行代码 System.out.println("AjaxCall" + request.getParameter("param")); 每一个值都需要对吧?难道没有可能通过对象传递它们吗? - J888
你可以将10个不同的值作为一个字符串,用管道符或任何标识符分隔,并在Java中以一个参数的形式获取该字符串,然后使用标识符进行拆分。这是一种选择,或者你可以使用JSON。 - karthick

2

你是在使用框架,还是仅仅使用纯Servlet?如果你使用了类似Struts的框架,那么所有这些答案都太复杂了。

我认为你只是使用了映射的Servlet,这意味着上面的答案是正确的,可以通过URL传递命名参数。你可以使用POST来隐藏这些命名参数,而不是GET。

以下是我使用Servlet的方法。但是,如果我是你并进行完整的项目,我会使用JSF来更容易地传递数据。

java

public void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    String payslipID = request.getParameter("payslipid");
}

js

<script>
var payslipid = $('#employee_payslip_id')
xmlhttp.open("POST","../payslip/pay",false);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("payslipid="+payslipid);
</script>

如前文所述,您必须单独获取所有参数(并在帖子中放置或获取数据),除非您进行了某些字符串列表的分离。这并不是一件荒谬的事情,因为您无论如何都需要将所有这些值分别分离到自己的变量中。
编辑:
上面的答案实际上已经说出了您需要做什么,但也许更清晰会有所帮助。在您的Struts配置文件中定义操作的位置,例如:
<action class="org.example.Payslip" name="payslip">
            <interceptor-ref name="params"/>
            <result name="success">/success.jsp</result>
</action>

请确保添加params拦截器,这样服务器就可以将参数映射到setter中。然后,您就不需要为每个发送的内容调用getparameter调用。

此外,如果您像上面那样映射,URL应该是类似于…/ payslip.action!pay?payslipid = 1234&employeeid = 1234。这将告诉使用payslip.class和pay函数。


1
实际上,我正在使用Struts2,这就是为什么struts2被定义为一个问题标签,并且我有大量的参数,而不仅仅是payslipid。 - J888
抱歉,我没有注意到 struts 标签。我正在处理一个非常大的 struts 项目,所以我认为我可能已经在上面解决了你的问题。 - dhockey
1
太好了,谢谢。但唯一的问题是我将被迫在我的操作类中使用一个很长的变量列表,所以如果我想将它们发送到另一个类,需要在我的函数调用中有一个很长的参数列表或创建一个新对象并将它们全部放入该对象的变量中,有没有什么解决方法? - J888
1
我的函数调用中有一长串参数,如otherclass.mymethod(var1,var2,var3,var4,.....)。 - J888
1
你所提到的与Struts2无关,而是与Struts1有关。 - user1386522

2
  • 您需要将您的表单转换为json格式(例如此处),并发送到后端
  • 然后,在Java中,您需要将json反序列化为Java对象(例如,使用Jackson

2

Struts2使用params拦截器来填充HTTP请求提交的表单值。

建议使用POST方法,这样如果您有敏感数据并且不希望在URL中反映出来。

参数名称由拦截器用于通过OGNL运行时传递,以求值表达式,并应该在valueStack中找到引用。

如果您没有初始化或注入由OGNL评估其引用的对象的依赖项,则会出现NullPointerException。因为您正在使用嵌套的bean,所有嵌套属性都应该是可访问和已初始化的(或至少Struts2知道如何创建这些对象),并且属于放置在值堆栈top上的操作类。


1
你需要使用ModelDriven接口。实现ModelDriven并重写其方法,然后使用modelDriven方法返回你的对象。 Struts2文档

你不需要使用 ModelDriven - Roman C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接