- Create a Dao method to fetch users by username. The method
uses the "like" keyword in the query with wildcards on both sides. So,
typing "ci" will return both "luciano"
and "pacific"
usernames.
- Add the following method to UserDao.java
public List getUsersBySearchString(String searchString);
- Add
the following method to UserDaoHibernate.java
public List getUsersBySearchString(String searchString) {
return getHibernateTemplate().find("from User u where u.username like '%"+searchString+"%'");
}
- Add a method to the service layer. The method
doesn't do
much. It just call the method with the same name on the Dao layer.
- Add the following method to UserManager.java
public List getUsersBySearchString(String searchString);
- Add
the following method to UserManagerImpl.java
public List getUsersBySearchString(String searchString) {
return dao.getUsersBySearchString(searchString);
}
-
Time for the web layer. Create a new Controller to handle the Ajax request and output the response. I have used a
MultiActionController because
I can group multiple Ajax related actions in one controller. Create a AjaxFrontController under in %APPFUSE%/src/web/../webapp/action.
import com.thetapenet.service.UserManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class AjaxFrontController extends MultiActionController {
private transient final Log log = LogFactory.getLog(AjaxFrontController.class);
private UserManager umgr = null;
public void setUserManager(UserManager userManager) {
this.umgr = userManager;
}
/**
* Only used for testing this tutorial !
*/
public ModelAndView ajaxFrontDemo(HttpServletRequest request,
HttpServletResponse response) {
return new ModelAndView("demoUser", "dummy", null);
}
public ModelAndView ajaxFrontGetUsers(HttpServletRequest request,
HttpServletResponse response) {
if (log.isDebugEnabled()) {
log.debug("Entering method...");
}
String userz = request.getParameter("user");
log.debug("AJAX - Fetching %" + userz + "%");
return new ModelAndView("autocompleteUsersXML", "users", umgr.getUsersBySearchString(userz));
}
}
Add the new controller bean definition to action-servlet.xml.
<bean id="ajaxFrontController" class="com.thetapenet.webapp.action.AjaxFrontController"/>
<property name="userManager" ref="userManager"/>
<bean/>
Finally add this property to the "urlMapping" bean on action-servlet.xml.
<prop key="/ajaxFront*.html"/>ajaxFrontController</prop/>
Now the AjaxFrontController's actions can be called using the key specified in the property as prefix: http://localhost:8080/myapp/ajaxFrontGetUsers.html.
The ajaxFrontGetUsers action is pretty simple. The "user" parameter is set by the AjaxTags and contains the text entered in the Ajaxified textbox on the page.
The action returns a "autocompleteUsersXML" view, setting the retrieved list of users in the request.
The "autocompleteUsersXML" view is not a JSP page but a custom View that has the sole responability to build and output the XML stream parsed by the AjaxTags. Check the next step.
-
Now comes the interesting part. Create a class named AutocompleteUsersView in the web layer.
I have created a new "view" package for this class:
import org.springframework.web.servlet.view.AbstractView;
import org.ajaxtags.helpers.AjaxXmlBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletOutputStream;
import java.util.Map;
import java.util.List;
public class AutocompleteUsersView extends AbstractView {
protected void renderMergedOutputModel(Map model, HttpServletRequest httpServletRequest,
HttpServletResponse response) throws Exception {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
List users = (List) model.get("users");
String xml = new AjaxXmlBuilder().addItems(users, "username", "username").toString();
ServletOutputStream out = response.getOutputStream();
out.print(xml);
out.close();
}
}
This class extends AbstractView, hence is responsability is to act as a MVC view (in this case the view is an XML stream containing the username
returned from the query).
The interesting part in the AutocompleteUsersView is the usage of the AjaxXmlBuilder utility class. The "addItems" method create the XML out
of the List containing the User objects returned from the query.
-
Add a ResourceBundleViewResolver bean to action-servlet.xml.
This resolver converts a view name specified in a bundle file into a concrete View. The bundle is typically defined in a properties file, located in the class path.
The default bundle basename is "views".
<bean id="xmlViewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="order" value="1"/>
</bean>
Add a "views.properties" file under %APPFUSE%/web/WEB-INF/classes with the following property:
autocompleteUsersXML.class=com.thetapenet.webapp.view.AutocompleteUsersView
-
The last step is to add a page to call the new Controller. Add a demoUser.jsp under %APPFUSE%/web/pages. This is pretty much a dummy page
to demonstrate the usage of the AjaxTags library.
<%@ include file="/common/taglibs.jsp" %>
<%@ taglib uri="http://ajaxtags.org/tags/ajax" prefix="ajax" %>
<!-- ajaxtags stuff -->
<script type="text/javascript" src="<c:url value='/scripts/ajaxtags.js'/>"></script>
<head>
</head>
<form method="post" action="">
<input type="text" id="user_name" name="user_name" size="40" value=""/>
<span id="indicator" style="display:none;"><img src="<c:url value="/images/indicator.gif"/>"/></span>
</form>
<ajax:autocomplete
baseUrl="${pageContext.request.contextPath}/ajaxFrontGetUsers.html"
source="user_name"
target="user_name"
className="autocomplete"
indicator="indicator"
minimumCharacters="1"
parameters="user={user_name}"
parser="new ResponseXmlToHtmlListParser()"/>
The most relevant entry in the page is the "autocomplete" ajax tags. The tag references the input text using the input text "id". Both "source" and "target"
are set to the same input text. You can set the target to a different input text to add even more "autocompletition" (check the demo application that
comes with AjaxTags).
The "baseUrl" parameter contains the url of the action to invoke to send the request.
The "parameters" tag property specifies a comma-separated list of parameters to pass to the action.
The "indicator" property references a span with the id set to "indicator". The span contains a fancy rotating gif that shows up when you digit something
in the textbox. The gif is part of the AjaxTags demo app.