版权提醒
本系列文章为原创内容。转载请注明文章来源。
一般的方法
我在使用 Ajax 时,遇到了需要返回多项数据的需求,我自然地想到了使用 JSON 的方法。
我查找了许多在 Struts2 中使用 JSON 的教程,给出的方法大都是使用 struts2-json-plugin ,然后在 struts.xml 中设置类似下面的项:
<!-- 需要继承struts-default和json-default -->
<package name="Login" extends="struts-default,json-default">
<action name="login">
<result>/login.jsp</result>
</action>
<action name="loginaction" class="com.hpe.struts.LoginAction">
<result type="json"><!-- 返回的数据类型为json -->
<param name="res">data</param><!-- 这个地方的data就是在LoginAction中定义的data,它必须要有getter、setter,这样就可以将data传递到前台页面上,LoginAction类中所有具有getter的字段都会被封装到一个类中,传递到前台 {"data":"{\"msg\":\"登录成功!\",\"status\":\"1\"}","mmp":2000} -->
</result>
</action>
</package>
因为这篇文章不介绍这种方法,如果需要,可以看看另一位大大的博客: Struts2中通过Ajax传递json数据 。
遇到的问题
也许这个方法没有问题,但我的项目在使用 Struts2 的同时,还需要使用 Spring Data JPA 操作数据库。
当我尝试使用上面的方法时,总是遇到这样的错误:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.chiyu.entity.CustomerEntity.bordersByCid, could not initialize proxy - no Session
这个问题看起来像是和 JPA 设置有关的错误,但只要不使用 JSON 作为的返回值类型,这个错误就会消失,而且一切有关数据库的操作也完全正常。
看来这个方法不适合我,只能另辟蹊径了。
我的解决方案
我们知道, JSON 类型的数据可以很方便地转换成字符串,也可以从字符串很方便地转回来。
而且我们知道,在 Struts2 中,使用 stream 类型作为 Ajax 的返回值,可以非常方便地传递字符串等内容。
那么,直接使用 Struts2 以 stream 形式向页面传递 JSON 格式的字符串不就行了。
具体方法
Action 内容
使用了 Alibaba 的 fastjson ,处理后台的 JSON 数据。
@Controller
public class CustomerManager extends ActionSupport {
//用于获取从页面返回的客户信息。
private CustomerEntity customer;
private List<CustomerEntity> customerList;
//用于对客户信息进行各种操作的服务层,由Spring Bean赋值
private CustomerService customerService;
//用于使用AJAX技术执行客户信息添加删除更新时向网页传递信息
private InputStream inputStream;
public CustomerEntity getCustomer() {
return customer;
}
public void setCustomer(CustomerEntity customer) {
this.customer = customer;
}
public List<CustomerEntity> getCustomerList() {
return customerList;
}
public void setCustomerList(List<CustomerEntity> customerList) {
this.customerList = customerList;
}
public CustomerService getCustomerService() {
return customerService;
}
@Autowired
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
//访问客户信息管理页面,并返回所有客户信息。
@Override
public String execute() throws Exception {
//返回所有客户信息
customerList = customerService.findAllCustomers();
return SUCCESS;
}
//添加或更新客户信息方法,使用AJAX,返回json字符串
public String addOrUpdateCustomer(){
//执行对一条客户信息的新增或修改
if (customer.getCid() == null || customer.getCid().isEmpty()){
customer.setCid(UUID.randomUUID().toString().replace("-", ""));
}
customer = customerService.insertOrUpdateCustomer(customer);
//创建JSON对象
JSONObject object = new JSONObject();
//向JSON对象中增加数据
object.put("result","操作成功");
object.put("cid",customer.getCid());
//将JSON对象转换成字符串,再转为utf-8字节流
inputStream=new ByteArrayInputStream(JSON.toJSONString(object).getBytes(StandardCharsets.UTF_8));
return "addOrUpdateCustomerResult";
}
}
注意事项:
private InputStream inputStream;
是 Struts 返回给页面的数据,需要有 get 和 set 方法。
Struts.xml 内容
<package name="background" namespace="/admin" extends="struts-default" strict-method-invocation="false">
<action name="customerManager" class="customerManager">
<result name="success">/admin/admin_customer.jsp</result>
<result name="addOrUpdateCustomerResult" type="stream">
<!-- 设置返回给浏览器的数据类型 -->
<param name="contentType">text/html</param>
<!--指定获取InputStream的方法,getInputStream(),约定:去掉get,后面部分使用camel写法 -->
<param name="inputName">inputStream</param>
</result>
</action>
</package>
注意事项:
因为我的项目集成了 Spring ,使用可以使用 class="customerManager"
这样的写法,如果没有使用 Spring ,请写完整类名。
页面中的 Ajax 方法
需要 jQuery 。
<!--对应提交按钮-->
function submitCustomerFunc(btn){
//防止多次提交,点击提交按钮后,此按钮失效
$(btn).attr("disabled",true);
//获得用户输入的值
let cid = $("#input_cid").val();
let cname = $("#input_cname").val();
let phone = $("#input_phone").val();
let address = $("#input_address").val();
let password = $("#input_password").val();
//使用 AJAX
$.ajax({
//请求发送的地址
url:"customerManager!addOrUpdateCustomer.action",
//使用post方式发送
type:"post",
//向服务器发送的内容
data:{"customer.cid":cid,"customer.cname":cname,"customer.phone":phone,"customer.address":address,"customer.password":password},
//接收到的数据类型
dataType:"text",
//请求失败后执行
error:function (){
alert("操作失败!");
//可以再次尝试提交
$(btn).attr("disabled",false);
},
//请求成功,但具体操作可能是失败的,如果操作失败,data中的内容将是包含错误信息的html文件。
success:function (data){
//如果是失败的,这样可以显示错误信息,为了防止最终用户看到后台错误信息,这个方法应当在开发结束后删除。
//alert(data);
// 尝试将可能是json字符串的data转化为json对象
let obj = jQuery.parseJSON(data);
//确保操作成功后执行以下内容
if (obj.result === "操作成功"){
//显示“操作成功”
alert(obj.result);
//获取服务器返回的用户id
cid = obj.cid;
//使用户能创建下一条新的记录。
$("#addCustomerButton").attr("disabled",false);
//移除用于接收用户输入的一行表格
$("#newLine").remove();
//创建一行表格,用于显示用户输入的结果
$("#customerList").append("<tr><th scope='row'>" + cid + "</th> <td>" + cname + "</td> <td>" + phone + "</td> <td>" + address + "</td> <td>" + password + "</td> <td> <div class='btn-group mr-2'> <button type='button' class='btn btn-sm btn-outline-secondary' onclick='updateCustomerFunc(this)'>修改</button><button type='button' class='btn btn-sm btn-outline-secondary' onclick='deleteCustomerFunc(this)'>删除</button></div></td></tr>'");
}else {
//可以再次尝试提交
$(btn).attr("disabled",false);
}
}
})
}