Skip navigation

Tag Archives: spring-mvc

So you want your page to have an ajax paging for your comments page or tabular data. Ajax paging means that every time you select a page (from page navigator) it will not reload or refresh the whole web page, instead it is only change the comments or tabular data area.

This article is only one from many techniques to accomplish this, we are going to make ajax paging using Java (Hibernate + Spring MVC) and JQuery.

The way for getting data for the selected page is actually simple, for example if selected page is 2 and page size is 10 you can make SQL query like:
MYSQL


select * from app_user limit 10,10;

Notes: In Mysql,  zero (0) is first index. The query will get records 11-20 from table “app_user

ORACLE


select * from (SELECT rbt_config.*, ROWNUM r FROM rbt_config) where r between 11 and 20;

Fortunately we are going to use Hibernate and dont have to create specific query for each databases.
Just use code like below and Hibernate will take care how he will make queries for the database we choose.

HIBERNATE

protected List listByPage(Class clazz, int firstResult, int maxResult) {
        String strQry = "from " + clazz.getName() + " c order by c.id desc";

        Query query = this.sessionFactory.getCurrentSession().createQuery(strQry);
        query.setFirstResult(10);
        query.setMaxResults(10);

        return query.list();
    }

After you get the data you simply display it on the page, that’s it. But the tricky part from paging is how do you want the page navigator to look like, there are page navigator with first and last page link/button, there are page navigator with previous and next page link/button, also page navigator with sequences of numbers link to select a page, etc.
It’s up to you how the page navigator will look like, for these example just see it by your self 🙂 .

I don’t put much code here, so just download the code and see it. Here is some of the screenshots:

Home

Comments Page 1

Comments Page 2

Tabular Data 1

Tabular Data 2

There are two examples I provide:  Comments page look a like and tabular data sample.
Every time we select a page from page navigator it will make ajax request to server (using JQuery) and replace/change the comments or tabular data area with new result without reload whole area. Also during make ajax request to server it will display loading ajax image.

Loading Ajax Image

You can download the code from here or here. It’s Java project using Maven, i’m usually open it using IntelliJ IDEA. To set up the data just run “com.ajax.paging.dao.SetUpData” from “src/test” folder, using IntelliJ IDEA  I just right click the file –> RUN, It will save arround 20 records to table “COMMENT” and “USER” for testing ajax paging.

Dont forget to edit “src/resources/hibernate.properties” to match your environtment.
In the “src/resources/app.properties” there two important keys:
app.page.size.default –> change the page size
If “app.page.size.default=6” it will display 6 records every page, and so on.

app.page.nav.trail –> change the page navigator trail
If “app.page.nav.trail=2” and selected page is 3 page navigator will look like 1 2 [3] 4 5 (two previous page and two next page) and so on.

Please build, package, and run in your favourite web server / servlet container. Download from here and here.

Advertisements

This article will show how to upload and download in web application using Spring-MVC. The application will upload any file format and save it to database, likewise when downloading it will read from database and open save download dialog.

Consider a form like this:

Here is html code:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
  <head><title>Upload and Download files using Spring</title></head>
  <body>
    <table width="80%" border="1" cellspacing="0" cellpadding="5">
        <tr>
            <th width="4%">No</th>
            <th width="30%">Filename</th>
            <th width="30%">Notes</th>
            <th width="16%">Type</th>
            <th width="20%">&nbsp;</th>
        </tr>
        <c:choose>
            <c:when test="${files != null}">
                <c:forEach var="file" items="${files}" varStatus="counter">
                    <tr>
                        <td>${counter.index + 1}</td>
                        <td>${file.filename}</td>
                        <td>${file.notes}</td>
                        <td>${file.type}</td>
                        <td><div align="center"><a href="download.htm?id=${file.id}">Download</a> /
                            <a href="delete.htm?id=${file.id}">Delete</a></div>
                        </td>
                    </tr>
                </c:forEach>
            </c:when>
        </c:choose>
    </table>

    <h2>Add New File</h2>
    <form action="upload.htm" method="post" enctype="multipart/form-data">
        <table width="60%" border="1" cellspacing="0">
            <tr>
                <td width="35%"><strong>File to upload</strong></td>
                <td width="65%"><input type="file" name="file" /></td>
            </tr>
            <tr>
                <td><strong>Notes</strong></td>
                <td><input type="text" name="notes" width="60" /></td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td><input type="submit" name="submit" value="Add"/></td>
            </tr>
        </table>
    </form>
  </body>
</html>

To upload a file from web page we need to set a form with property enctype="multipart/form-data" . This will use by action/controller how to handle the data.

To save a binary file to database we use column with type Blob. I’m using Mysql database, i’m choose column with type longblob. There’s three type of blob in Mysql (other is blob and mediumblob), i’m using longblob so it can store more bigger file. This is create table script:

 

CREATE TABLE `files` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `filename` varchar(100) NOT NULL,
  `notes` varchar(100) default NULL,
  `type` varchar(40) default NULL,
  `file` longblob default NULL,
  PRIMARY KEY  (`id`)
);

 

As we can see column ‘file’ type longblob, we wil use to store the binary of a file. Column ‘filename’ to store original file name, column ‘type’ to save the type of the file, and column ‘notes’ is optional.

And here is the java bean to represent the table:

package com.spring.example.bean;
public class Files {
    private int id;
    private String filename;
    private String notes;
    private String type;
    private byte[] file;

    // please make setter and getter
}

For the blob type column, i use bytes array rather that Java Blob type. It will suit accross different databases blob type.

Service/manager/DAO
For database layer we’re using Spring JDBC, so we create service class that extends JdbcDaoSupport class.

package com.spring.example.web;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.spring.example.service.FilesService;
import com.spring.example.bean.Files;
import java.util.List;

public class FilesService extends JdbcDaoSupport {
    String query = null;

    /**
     * find
     */
    public Files find(int id) {
        query = "select * from files where id = ?";

        try {
            Files file = (Files) getJdbcTemplate().queryForObject(query, new Object[] {id},
                new RowMapper() {
                    Files fl;
                    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                        fl = new Files();
                        fl.setId(rs.getInt(1));
                        fl.setFilename(rs.getString(2));
                        fl.setNotes(rs.getString(3));
                        fl.setType(rs.getString(4));
                        fl.setFile(rs.getBytes(5));

                        return fl;
                    }
            });

            return file;
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * listAll
     */
    public List<Files> listAll() {
        query = "select id, filename, notes, type from files";

        try{
            List<Files> files = getJdbcTemplate().query(query, new BeanPropertyRowMapper(Files.class));

            return files;
        } catch(Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * save
     */
    public void save(final Files file) {
        query = "insert into files (filename, notes, type, file) values (?, ?, ?, ?)";

        try {
            synchronized(this) {
                getJdbcTemplate().update(new PreparedStatementCreator() {

                    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                        PreparedStatement statement = con.prepareStatement(query);
                        statement.setString(1, file.getFilename());
                        statement.setString(2, file.getNotes());
                        statement.setString(3, file.getType());
                        statement.setBytes(4, file.getFile());
                        return statement;
                    }
                });
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * delete
     */
    public void delete(int id) {
        query = "delete from files where id = ?";

        try {
            getJdbcTemplate().update(query, new Object[] {id});
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

File List Form
Here is the controller that will query all the files that we had upload, send it to page so it will display all uploaded files, then we can download or delete it. And we can upload a new file.

package com.spring.example.web;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.spring.example.service.FilesService;
import com.spring.example.bean.Files;
import java.util.List;

public class FilesForm extends AbstractController {
    private FilesService filesService;

    public void setFilesService(FilesService filesService) {
        this.filesService = filesService;
    }

    protected ModelAndView handleRequestInternal(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        List<Files> files = this.filesService.listAll();

        return new ModelAndView("files", "files", files);
    }
}

Files Controller
This is a Spring MultiActionController so i dont need separate controller class file to upload, download, and delete a file.

package com.spring.example.web;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.util.FileCopyUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.spring.example.bean.Files;
import com.spring.example.service.FilesService;

public class FilesController extends MultiActionController {
    private FilesService filesService;

    public void setFilesService(FilesService filesService) {
        this.filesService = filesService;
    }

    /**
     * upload
     */
    public ModelAndView upload(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile multipartFile = multipartRequest.getFile("file");

        Files file = new Files();
        file.setFilename(multipartFile.getOriginalFilename());
        file.setNotes(ServletRequestUtils.getStringParameter(request, "notes"));
        file.setType(multipartFile.getContentType());
        file.setFile(multipartFile.getBytes());

        this.filesService.save(file);

        return new ModelAndView("redirect:files.htm");
    }

    /**
     * download
     */
    public ModelAndView download(HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        int id = ServletRequestUtils.getRequiredIntParameter(request, "id");

        Files file = this.filesService.find(id);

        response.setContentType(file.getType());
        response.setContentLength(file.getFile().length);
        response.setHeader("Content-Disposition","attachment; filename=\"" + file.getFilename() +"\"");

        FileCopyUtils.copy(file.getFile(), response.getOutputStream());

        return null;

    }

    /**
     * delete
     */
    public ModelAndView delete(HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        int id = ServletRequestUtils.getRequiredIntParameter(request, "id");

        this.filesService.delete(id);

        return new ModelAndView("redirect:files.htm");
    }
}

applicationContext.xml
Here is the applicationContext.xml, please change proper value to match your environtment:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- datasource -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test">
        </property>
    </bean>

    <!-- template -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- services -->
    <bean id="filesService" class="com.spring.example.service.FilesService">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
</beans>

dispatcher-servlet.xml
The dispatcher-servlet.xml contains list of mapping url address to controller class, i use SimpleUrlHandlerMapping class for url handler mapping. And there’s two view resolver, the basic InternalResourceViewResolver and CommonsMultipartResolver to handle file upload, i set the ‘maxUploadSize’ property to 5Mb.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- mapping -->
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="files.htm">filesForm</prop>
                <prop key="upload.htm">filesController</prop>
                <prop key="download.htm">filesController</prop>
                <prop key="delete.htm">filesController</prop>
            </props>
        </property>
    </bean>

    <!-- The view resolver -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5242880" />
    </bean>

    <!-- controller -->
    <bean id="filesForm" class="com.spring.example.web.FilesForm">
        <property name="filesService" ref="filesService"/>
    </bean>

    <bean id="filesController" class="com.spring.example.web.FilesController">
        <property name="filesService" ref="filesService"/>
        <property name="methodNameResolver">
            <bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
                <property name="mappings">
                    <props>
                        <prop key="/upload.htm">upload</prop>
                        <prop key="/download.htm">download</prop>
                        <prop key="/delete.htm">delete</prop>
                    </props>
                </property>
            </bean>
        </property>
    </bean>
</beans>

Common Errors/Exception when upload a file (in Mysql)
Commons error during file upload process is how big size of file can be transferred to a server or save to a databases.
If you experienced similiar error like this, when using mysql database:

 

Packet for query is too large (1217245 > 1047552). You can change this value
on the server by setting the max_allowed_packet' variable.; nested exception is
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1217245 > 1047552).
You can change this value on the server by setting the max_allowed_packet' variable.

 

or

 

Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too
large (1217245 > 1047552). You can change this value on the server by setting
the max_allowed_packet' variable.

 

In Unix/Linux system open file “/etc/my.cnf“, look for the max_allowed_packet string and set the max value you want to.

Here, here and here is the code.