before I upgrade the struts from 2.3.x to 2.5.8, the JSON can return data to me,but now return JSON value is empty in struts2.5.8, whatever what type i have put. here is my code:
TestController.java
public class TestingController implements ModelDriven<Object> {
private ArrayList<Test> testList = null;
public ArrayList<Test> getTestList() { return testList;}
public String tableData() {
jsonMap = new HashMap<String, Object>();
testList = getTestListBySomething();
if(testList!=null && testList.size()>0){
jsonMap.put("test", testList);
}
}
also my struts.xml:
<package name="default" namespace="" extends="rest-default,struts-default" strict-method-invocation="false">
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult"/>
</result-types>
</package>
I have checked that the testList have data and size, but in the response on ajax , it show:
{"test":""}
What wrong of my coding?
In your strust xml add below parameter.
<param name="root">#action</param>
EX :
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult">
<param name="noCache">true</param>
<param name="excludeNullProperties">true</param>
<param name="root">#action</param>
<param name="ignoreHierarchy">false</param>
<param name="excludeProperties">errors</param>
</result-type>
</result-types>
Related
Hi am struggling to play video file in jsp file from system location using struts2. But if i place video file(Sample.mp4) under web-content in eclipse and just use the video tag in jsp with fileName like below it will get play.
<source src="Sample.mp4" type="video/mp4"/>
How do i play the video which is there in system location example d:/video/sample.mp4 ?
Action class
public class DownloadAction extends ActionSupport {
private InputStream fileInputStream;
private String fileToDownload = "D://video//Sample.mp4";
private String fileName;
private String contentType = "video/mp4";
public String execute() throws Exception {
fileInputStream = new FileInputStream(fileToDownload);
return SUCCESS;
}
public InputStream getFileInputStream() {
return fileInputStream;
}
public void setFileInputStream(InputStream fileInputStream) {
this.fileInputStream = fileInputStream;
}
public String getFileToDownload() {
return fileToDownload;
}
public void setFileToDownload(String fileToDownload) {
this.fileToDownload = fileToDownload;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}
struts.xml
<action name="download" class="com.sample.actions.DownloadAction">
<result name="success" type="stream">
<param name="contentType">${contentType}</param>
<param name="inputName">fileInputStream</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<param name="bufferSize">1024</param>
</result>
</action>
in Jsp
<body>
<%
String url = request.getScheme() + "://" + request.getServerName()
+ ":" + request.getServerPort() + request.getContextPath();
url = url + "//download";
%>
<video width="320" height="240" controls>
<source src=<%=url%>>
</video>
</body>
Here is an jsp page to for video display
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<video width="400" controls>
<source src="<s:url value="videoStream" />" type="video/mp4"/>
<source src="mov_bbb.ogg" type="video/ogg">
Your browser does not support HTML5 video.
</video>
</body>
</html>
Map the s:url request to struts action action in struts.xml
<struts>
<package name="user" namespace="/" extends="struts-default">
<action name="videoStream" class="com.pradeep.videostream.VideoStreamingAction">
<result name="success" type="stream">
<param name="contentType">${yourContentType}</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">attachment;filename="${yourFileName}"</param>
<param name="bufferSize">1024</param>
</result>
</action>
</package>
</struts>
in the action class am fething video file from file system and doing streaming
public class VideoStreamingAction extends ActionSupport {
private InputStream inputStream;
private String yourContentType;
// getters and setters
public String execute() throws Exception {
yourContentType = "video/mp4";
File file =new File("D://svn videos//Create Java Spring Web MVC Project With Maven [EDITED].mp4");
setInputStream(new ByteArrayInputStream(FileUtils.readFileToByteArray(file)));
return SUCCESS;
}
}
I am trying to understand how to use JSON and in the process I'm trying to get a JSON response from Struts2 action and display an alert for the response. For this I'm using Ajax POST in JavaScript as follows:
function checkButtonClick(id){
var btnSave = 'saveAttendees';
var atNameList = $('#attName'+id).val();
var ptNameList = $('#postName'+id).val();
var aId = $('#at_id'+id).val();
alert("here");
var arr = {buttonName: btnSave,
attendeesNameList: atNameList,
attendeesPostList: ptNameList,
hidden_At_id: aId
};
$.ajax({
data: arr,
type: 'POST',
dataType: 'json',
url:"meeting_record_form",
success:function(result){
alert(result.myMsg);
},
error:function(result){
alert("error");
}
});
}
My Action class contains a String field that I'm trying to display in alert as JSON response. But I'm finding problem doing this. What am I missing or doing wrong?
My action class is as follows:
private String myMsg;
public String getMyMsg() {
return myMsg;
}
public void setMyMsg(String myMsg) {
this.myMsg = myMsg;
}
private String updateAttendeesRecord() {
meetingRecordService.updateAttendeesRecord(attendeesListMethod(), meeting_record);
setMyMsg("Update Successful!");
return SUCCESS;
}
struts.xml file:
<package name="default" extends="struts-default, json-default">
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult" />
</result-types>
<interceptors>
<interceptor name="json" class="org.apache.struts2.json.JSONInterceptor" />
</interceptors>
<action name="meeting_record_form" class="com.task.action.MeetingRecordAction" method="updateAttendeesRecord">
<result name="success" type="json" />
</action>
</package>
My pom.xml:
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
<version>2.3.15</version>
</dependency>
In the action configuration you should not override the default configuration from json-default package just extend it and all. Also json-default extend a struts-default, so multiple inheritance is not required.
<package name="default" extends="json-default">
<action name="meeting_record_form" class="com.task.action.MeetingRecordAction" method="updateAttendeesRecord">
<result name="success" type="json" />
</action>
</package>
The problem in your Action class MeetingRecordAction, method updateAttendeesRecord is private, it should be public
public String updateAttendeesRecord() {
meetingRecordService.updateAttendeesRecord(attendeesListMethod(), meeting_record);
setMyMsg("Update Successful!");
return SUCCESS;
}
I've solved my problem by adding myMsg on the json result. Thanks for all the help
In my spring MVC 4.1.5 application configured to use Thymeleaf 2.1.4 (before it was using JSP and it worked fine), i am unable to return a JSON response.
It always returns a full HTML page weather my request mapping is in a #RestController or if its annotated with #responsebody
Here are the controllers
in an #controller class, i have below mapping
#RequestMapping(value = { "/", "/land", "/login" }, method = RequestMethod.GET)
public String getLogin(Model model, HttpSession session) {
session.setAttribute("login", "none");
System.out.println(programId);
model.addAttribute("signUpForm", new SignUpForm());
return "login";
}
and in #RestController class, below is the post method for same URL
#RequestMapping(value = {"/login" }, method = RequestMethod.POST )
public #ResponseBody HashMap<String, Object> login2(#RequestBody SignUpForm signUpForm, HttpServletRequest request,
HttpServletResponse httpServletResponse, HashMap<String, Object> mo, HttpSession session ) {
User user = userDao.findUserByName(signUpForm.getUserName());
if (user != null && encoder.matches(signUpForm.getPassword(), user.getPassword())&& user.getProgram_id()==3) {/* && user.getProgram_id()==3*/
session.setMaxInactiveInterval(1200);
System.out.println(session.getMaxInactiveInterval()+":"+session.getLastAccessedTime()+":"+session.getCreationTime()+":"+session.getServletContext().getContextPath());
session.setAttribute("login", "success");
mo.put("redirect", "/home");
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
session.setAttribute("urip", ipAddress);
return mo;
} else {
mo.put("error", "Login failed. Please check your credentials");
return mo;
}
}
Below is my xml configuration
<context:component-scan base-package="com.company.cardholder" />
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler />
<mvc:interceptors>
<bean class="com.company.cardholder.session.interceptors.URLInterceptor" />
</mvc:interceptors>
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/thymeleaf/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<!-- Template cache is set to false (default is true). -->
<property name="cacheable" value="false" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
Here is my JSON call
$.ajax({
type: 'POST',
url: $form.attr('action'),
data: JSON.stringify({
userName: $form.find('#userName').val(),
password: $form.find('#password').val(),
}),
contentType: "application/json",
/*dataType: 'json',*/
complete: function(data) {
console.log(data);
if (data.redirect) {
// data.redirect contains the string URL to redirect to
window.location.href = data.redirect;
}else if(data.error){
$messageError.text(data.error);
$messageError.removeClass('hidden');
$messageSuccess.addClass('hidden');
}
}
});
Ok. Here is what i figured out to make it work but i still am not sure of the reason.
public #ResponseBody HashMap<String, Object> login2(#RequestBody SignUpForm signUpForm, HttpServletRequest request,
HttpServletResponse httpServletResponse, HashMap<String, Object> mo, HttpSession session ){
////
}
In the above method signature, i was "injecting" a hashmap. And spring framework default or some unknown config decided to inject a "Binding Result aware Hashmap." I am not sure what difference it would have made. But to fix it, i had to do a
HashMap<String, Object> mo=new HashMap<String, Object>;
inside the method body and remove the injected hashmap.
If anyone is able to understand this behaviour, please explain it. I feel i missed something basic in my awareness of spring framework.
Can anyone enlighten me in what scenarios I would get the following error in the log?
Struts2 JasonInterceptor Content type must be 'application/json' or 'application/json-> rpc'. Ignoring request with content type application/x-www-form-urlencoded
I also notice that in the IE it shows a debug message as follows(not sure if these 2 messages are related):
DEBUG: please consider using a mimetype of text/json-comment-filtered to avoid potential >security issues with JSON endpoints
DEBUG: [SyntaxError: Syntax error]
I specifically changed my s:form enctype attribute as follows and still couldnt get rid of this message:
<s:form id="dealerForm" action="AjaxAutocompleterAction"
enctype="text/json-comment-filtered">
</s:form>
and this as well (didnt work again)
<s:form id="dealerForm" action="AjaxAutocompleterAction"
enctype="application/json">
</s:form>
any ideas?
*************Update - 1*****************
More information about the code I am working with follows:
My AjaxAutocompleter.jsp containing the linked autocompleters:
<s:form id="dealerForm" action="AjaxAutocompleterAction"
enctype="text/json-comment-filtered">
<sx:autocompleter id="dealer" name="dealer" searchType="substring"
label="Dealer" list="dealerList" listKey="name" listValue="name"
showDownArrow="false" valueNotifyTopics="/notifyBranch"
errorNotifyTopics="/error" beforeNotifyTopics="/before"
forceValidOption="true" loadMinimumCount="3" />
<sx:autocompleter id="branch" name="branch" searchType="substring"
label="Branch" list="branchList" showDownArrow="false"
listenTopics="/notifyBranch" formId="dealerForm"
formFilter="function(paramName){return true;}"
valueNotifyTopics="/notifyRep" beforeNotifyTopics="/before"
afterNotifyTopics="/after" forceValidOption="true"
loadMinimumCount="0" loadMinimumCount="3" />
<sx:autocompleter id="representative" name="representative"
searchType="substring" label="Rep" list="repList"
showDownArrow="false" forceValidOption="true" loadMinimumCount="0"
formId="dealerForm" formFilter="function(paramName){return true;}"
listenTopics="/notifyRep" beforeNotifyTopics="/before"
afterNotifyTopics="/after" loadMinimumCount="3" />
<textarea name="mytextarea" id="mytextarea" rows="25" cols="190"></textarea>
</s:form>
struts.xml
<package name="ajax" extends="json-default">
<action name="AjaxAutocompleterAction" class="com.frk.gid.action.AjaxAutocompleterAction">
<interceptor-ref name="json"/>
<interceptor-ref name="params">
<param name="ordered">true</param>
</interceptor-ref>
<interceptor-ref name="prepare" />
<result type="json" />
<result name="success">/AjaxAutocompleter.jsp</result>
</action>
</package>
my model classes
public class Representative {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
public class Branch {
private String name;
private List<Representative> representatives;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setRepresentatives(List<Representative> representatives) {
this.representatives = representatives;
}
public List<Representative> getRepresentatives() {
return representatives;
}
#Override
public String toString() {
return name;
}
}
public class Dealer {
private String name;
private List<Branch> branches;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
public List<Branch> getBranches() {
return branches;
}
#Override
public String toString() {
return name;
}
}
my prepare method
#Override
public void prepare() throws Exception {
logger.info("Prepare Started ...");
ServletActionContext.getResponse().setContentType(
"text/json-comment-filtered");
dealerList = new ArrayList<Dealer>();
int branchCounter = 0;
int repCounter = 0;
for (int i = 0; i < 5; i++) {
Dealer d = new Dealer();
List<Branch> branches = new ArrayList<Branch>();
for (int j = 0; j < 3; j++) {
Branch b = new Branch();
b.setName("BRANCH-" + branchCounter++);
List<Representative> representatives = new ArrayList<Representative>();
for (int k = 0; k < 2; k++) {
Representative rep = new Representative();
rep.setName("REP-" + repCounter++);
representatives.add(rep);
}
b.setRepresentatives(representatives);
branches.add(b);
}
d.setName("DEALER-" + i);
d.setBranches(branches);
dealerList.add(d);
if (this.dealer == null && i == 0) {
setDealer(d.getName());
}
// Populate DBR Hierarchy for the selected dealer.
if (this.dealer != null && this.dealer.equals(d.getName())) {
branchList = new ArrayList<String>();
int bCount = 0;
for (Branch b : branches) {
branchList.add(b.getName());
if (this.branch == null && bCount++ == 0) {
setBranch(b.getName());
}
if (this.branch != null && this.branch.equals(b.getName())) {
repList = new ArrayList<String>();
for (Representative r : b.getRepresentatives()) {
repList.add(r.getName());
}
if ((this.representative == null && repList.size() > 0)
|| (this.representative != null && !repList
.contains(this.representative))) {
setRepresentative(repList.get(0));
}
}
}
}
}
Ok .. finally after much struggle, I did manage to solve this myself . the clue lies in my autocompleter definition where I had to use dataFieldName always whenever I used the href.
Also, I couldnt get to load the first level hierarchy (in my case Dealer) to work with the href -i had to explicitly call the action and use the local variable.
I am posting my modified code so it could come in handy for other learners :-) Have fun !!!
My Updated jsp
<s:url id="dbrList" action="AjaxAutocompleterAction"
encode="text/json-comment-filtered"/>
<s:action name="AjaxAutocompleterAction" id="myDBRAction" />
<sx:autocompleter id="dealerList" name="dealer" searchType="substring"
label="Dealer" showDownArrow="false" valueNotifyTopics="/notifyBranch"
errorNotifyTopics="/error" beforeNotifyTopics="/before"
forceValidOption="true" loadMinimumCount="1"
list="%{#myDBRAction.dealerList}" />
<sx:autocompleter id="branchList" name="branch" searchType="substring"
label="Branch" list="branchList" showDownArrow="false"
listenTopics="/notifyBranch" formId="dealerForm"
formFilter="function(paramName){return true;}"
valueNotifyTopics="/notifyRep" beforeNotifyTopics="/before"
afterNotifyTopics="/after" errorNotifyTopics="/error"
forceValidOption="true" loadMinimumCount="1" href="%{dbrList}"
list="branchList" dataFieldName="branchList" />
<sx:autocompleter id="repList" name="representative"
searchType="substring" label="Rep" list="repList"
showDownArrow="false" forceValidOption="true" formId="dealerForm"
formFilter="function(paramName){return true;}"
listenTopics="/notifyRep" beforeNotifyTopics="/before"
errorNotifyTopics="/error" afterNotifyTopics="/after"
loadMinimumCount="1" href="%{dbrList}" dataFieldName="repList" />
My updated struts.xml
<package name="ajax" extends="json-default">
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult" />
</result-types>
<action name="AjaxAutocompleterAction" class="com.frk.gid.action.AjaxAutocompleterAction">
<interceptor-ref name="json">
<param name="contentType">application/json</param>
</interceptor-ref>
<interceptor-ref name="jsonValidation" />
<interceptor-ref name="params">
<param name="ordered">true</param>
</interceptor-ref>
<interceptor-ref name="prepare" />
<result name="success" type="json">
<param name="contentType">text/html</param>
</result>
</action>
</package>
How can I filter logging based on a logged exception's message?
Code looks like this:
try {
someService.DoSomeWorkflow();
} catch(Exception e) {
log.Error("Hey I have an error", e);
}
Config looks like this:
<appender name="EventLogger" type="log4net.Appender.EventLogAppender">
<applicationName value="foo" />
<layout type="log4net.Layout.PatternLayout" value="PID:%P{pid}: %message" />
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="TextInsideTheException" />
</filter>
</appender>
I'm finding that I can filter only on the logged message ("Hey I have an error") but it seemingly ignores the exception's message. Since this is in our production environment I can't make any code changes so I can't change the logged message. Is there some configuration that would specify to also check the exception's message?
By subclassing FilterSkeleton, you can implement a filter that evaluates the exception text. Or exception type for that matter.
Here are basic implementations based on Peter's accepted answer
using System;
using log4net.Core;
namespace log4net.Filter
{
public abstract class ExceptionFilterBase : FilterSkeleton
{
public override FilterDecision Decide(LoggingEvent loggingEvent)
{
if (loggingEvent == null)
throw new ArgumentNullException("loggingEvent");
var str = GetString(loggingEvent);
if (StringToMatch == null || string.IsNullOrEmpty(str) || !str.Contains(StringToMatch))
return FilterDecision.Neutral;
return AcceptOnMatch ? FilterDecision.Accept : FilterDecision.Deny;
}
protected abstract string GetString(LoggingEvent loggingEvent);
public string StringToMatch { get; set; }
public bool AcceptOnMatch { get; set; }
}
public class ExceptionMessageFilter : ExceptionFilterBase
{
protected override string GetString(LoggingEvent loggingEvent)
{
return loggingEvent.ExceptionObject == null
? null : loggingEvent.ExceptionObject.Message;
}
}
public class ExceptionTypeFilter : ExceptionFilterBase
{
protected override string GetString(LoggingEvent loggingEvent)
{
return loggingEvent.ExceptionObject == null
? null : loggingEvent.ExceptionObject.GetType().FullName;
}
}
public class ExceptionStackFilter : ExceptionFilterBase
{
protected override string GetString(LoggingEvent loggingEvent)
{
return loggingEvent.ExceptionObject == null
? null : loggingEvent.ExceptionObject.StackTrace;
}
}
}
Configuration file
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Client.log" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{yyyy/MM/dd HH:mm:ss,fff} [%-5level] %logger - %message%newline" />
</layout>
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="Token is not valid." />
<acceptOnMatch value="false" />
</filter>
<filter type="log4net.Filter.ExceptionMessageFilter, YourAssembly">
<stringToMatch value="Application is not installed." />
<acceptOnMatch value="false" />
</filter>
<filter type="log4net.Filter.ExceptionTypeFilter, YourAssembly">
<stringToMatch value="System.Deployment.Application.DeploymentException" />
<acceptOnMatch value="false" />
</filter>
<filter type="log4net.Filter.ExceptionStackFilter, YourAssembly">
<stringToMatch value="at System.Deployment.Application.ComponentStore.GetPropertyString(DefinitionAppId appId, String propName)" />
<acceptOnMatch value="false" />
</filter>
</appender>
Try this:
log.Error("Hey I have an error: " + e.Message);
Edit: Sorry, didn't see that you cannot change that line...