Thứ Năm, 2 tháng 1, 2014

Xử lý File Upload trong Spring MVC

Để upload file từ client lên server ta sử dụng thư viện apache common-io và giao diện MultipartResolver của Spring.
Example lấy từ đây http://diepviends.blogspot.com/2013/12/xu-ly-form-trong-spring-mvc.html
Đầu tiên add các thư viện cần thiết vào
mở file pom.xml thêm các dependency sau:

            commons-io
            commons-io
            2.1
        

            javax
            javaee-web-api
            6.0
            provided
        
Cấu hình bean cho dispatcher servlet
Vào /WEB-INF/spring/appServlet/servlet-context.xml định nghĩa bean xử lý MultipartFile

bây giờ cấu hình cho dispatcher servlet xử lý multipart vào web.xml thêm đoạn như sau:

  appServlet
  org.springframework.web.servlet.DispatcherServlet
  
   contextConfigLocation
   /WEB-INF/spring/appServlet/servlet-context.xml
  
  1
  
   5000000
  
 
Xong việc cấu hình.
xử lý file upload thì có 2 cách:
Cách 1: lưu trực tiếp file vào DB, dữ liệu file được lưu trữ là kiểu binary
Cách 2: lưu file vào một thư mục nào đó trên server và sau đó lưu trữ đường dẫn vào DB
Cách thứ 2 thường được sử dụng đối với ứng dụng có upload image từ client
Trong ví dụ này, ta sẽ demo cả 2 cách xử lý trên (cũng tương tự nhau)
Ví dụ của ta sẽ lưu dữ liệu image của product ( kiểu byte) vào trường image (cách 1)
và upload ảnh vào thư mục /resources/upload trên server sau đó lưu đường dẫn của file ảnh được upload lên server vào trường imagePath.(cách 2)
Cụ thể Product class sẽ như sau:
package vn.ds.store.domains;

import java.io.Serializable;

public class Product implements Serializable {
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 private String name;
 private String price;
 private byte[] image;
 private String imagePath;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getPrice() {
  return price;
 }

 public void setPrice(String price) {
  this.price = price;
 }

 public byte[] getImage() {
  return image;
 }

 public void setImage(byte[] image) {
  this.image = image;
 }

 public String getImagePath() {
  return imagePath;
 }

 public void setImagePath(String imagePath) {
  this.imagePath = imagePath;
 }
 
}
File createProduct.jsp sẽ được sửa như sau:
  
  
create
Name
Price
Image
Chú ý thêm thuộc tính cho form tag để xử lý upload: enctype="multipart/form-data"
file listProduct.jsp sẽ là:

   
List of products
Name Price Image imagePath
${p.name} ${p.price}
Bây giờ ta sẽ viết phần quan trọng nhất - controller xử lý upload ProductController.java
package vn.ds.store.controllers;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import vn.ds.store.domains.Product;
import vn.ds.store.validators.ProductValidator;

@Controller
@RequestMapping("product")
public class ProductController {

 private ProductValidator validator = new ProductValidator();

 @RequestMapping(value = "create", method = RequestMethod.GET)
 public String doGet(Model model) {
  model.addAttribute("product", new Product());
  return "createProduct";
 }

 @RequestMapping(value = "save", method = RequestMethod.POST)
 public String doPost(@ModelAttribute Product product, Model model,
   BindingResult errors,
   @RequestParam(value = "file", required = false) MultipartFile file,
   HttpServletRequest request) {
  validator.validate(product, errors);
  if (errors.hasErrors()) {
   return "createProduct";
  }
  if (file != null) {
   byte[] fileContent = null;
   try {
    InputStream inputStream = file.getInputStream();    
    if (inputStream == null)
     System.out.println("File inputstream is null");
    // cach 1 - luu truc tiep
    fileContent = IOUtils.toByteArray(inputStream);    
    product.setImage(fileContent);    
    // cach 2 - upload vao thu muc
    String path = request.getSession().getServletContext().getRealPath("/") + "resources/upload/";
    FileUtils.forceMkdir(new File(path));
    File upload = new File (path + file.getOriginalFilename());
    file.transferTo(upload);
    String imagePath = request.getContextPath() + "/resources/upload/" + file.getOriginalFilename();
    product.setImagePath(imagePath);
    request.getSession().setAttribute("product", product);
    IOUtils.closeQuietly(inputStream);
   } catch (IOException ex) {
    System.out.println("Error saving uploaded file");
   }
  }
  ArrayList lst = new ArrayList();
  lst.add(product);
  model.addAttribute("products", lst);
  return "listProduct";
 }

 @RequestMapping(value = "/image", method = RequestMethod.GET)
 @ResponseBody
 public byte[] downloadImg(HttpServletRequest request) {
  Product product = (Product) request.getSession()
    .getAttribute("product");
  if (product != null)
   return product.getImage();
  else
   return null;
 }
}
Ở đây, ta lưu dữ liệu vào session để lấy ra sau (thông thường là lưu vào database, ở đây đang là demo). Cách 1 ta sẽ lưu dữ liệu vào biến image bằng hàm
IOUtils.toByteArray(inputStream); 
Sau đó ta định nghĩa một url mà để gọi đến trong src của thẻ img
url này chỉ gửi xuống client dữ liệu của image nên ta sử dụng @ResponseBody của spring hỗ trợ để làm việc đó (search google.com để biêt thêm chi tiết), dưới jsp ta chỉ cần gọi đến url này
Cách 2 ta sẽ coppy ảnh vào thư mục /resoures/upload để lấy đường dẫn vật lý trên server để tạo file ta dùng lệnh này:
String path = request.getSession().getServletContext().getRealPath("/") + "resources/upload/";
và để hiển thị file trên html, thẻ img chỉ hiển thị đường dẫn internet, ta sẽ lấy đường dẫn theo lệnh sau:
String imagePath = request.getContextPath() + "/resources/upload/" + file.getOriginalFilename();
và cuối cùng lệnh coppy data
file.transferTo(upload);
Kết quả:



source code:
https://www.mediafire.com/?4b23hkdzfhwil4g

Thanks & Regards!

Thứ Tư, 1 tháng 1, 2014

Ckeditor trong Spring MVC

Để áp dụng một rich-text ta sử dụng ckeditor: http://ckeditor.com/download (basic package, standard package, full package) và jquery http://jquery.com/download/ example lấy từ đây: http://diepviends.blogspot.com/2013/12/xu-ly-form-trong-spring-mvc.html
Trước tiên ta thêm ckeditor và jquery vào resources

Trong Product class ta thêm description về product đó
package vn.ds.store.domains;

import java.io.Serializable;

public class Product implements Serializable {
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 private String name;
 private String price;
 private String description;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getPrice() {
  return price;
 }

 public void setPrice(String price) {
  this.price = price;
 }

 public String getDescription() {
  return description;
 }

 public void setDescription(String description) {
  this.description = description;
 }
}
Thêm link của ckeditor và jquery



apply ckeditor thì có 2 cách:
 Cách 1: sử dụng ngay trong hàm ready của jquery

Cách 2: viết script trong body tag
    Description


    
 


   
Kết quả:


source code:
http://www.mediafire.com/download/br9fc35go9f572t/Store_ckeditor.rar
Thanks & Regard!

Template với Apache Tiles trong Spring MVC

Khi xây dựng một ứng dụng web, ta thường đặt nội dung trang web trong các template, để trình bày theo một bố cục nhất định. Tương tự như trong aspx có master page,  công nghệ jsp cũng hộ trợ template nhờ thẻ <%@include file ="xxx.jsp"%>
Nếu không sử dụng cách trên, Apache Tiles là một lựa chọn phổ biến trong jsp technology.
Apache Tiles là một fw độc lập, có thể tích hợp với nhiều fw khác như Struts, JSF, Spring..
Có thể tìm hiểu thêm thông tin trên google và trên trang chủ của Apache Tiles https://tiles.apache.org/
Example sẽ lấy từ đây: http://diepviends.blogspot.com/2013/12/xu-ly-form-trong-spring-mvc.html
Ví dụ của chúng ta sẽ trình bày theo bố cục sau:


Đầu tiên import các thư viện cần thiết-> thêm dependency vào pom.xml

  
   org.apache.tiles
   tiles-core
   2.2.2
   
    
     commons-logging
     commons-logging
    
   
  
  
   org.apache.tiles
   tiles-jsp
   2.2.2
  
Hiện tại Tiles đã có version 3, trong bài viết này ta sử dụng tiles 2 (đang rất phổ biến trong các ứng dụng j2ee)
Ta xây dựng các phần cho template:
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
Header
menu.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
menu
footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
footer
default.jsp
<tiles:insertAttribute name="title" />
Ở đây ta dùng tag
để chèn nội dung vào tương tự như
<%@include file ="xxx.jsp"%>
và import vào taglib
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>

Tiếp theo ta cấu hình cho dispatcher servlet


    
        
    
    
    
        
            
                /WEB-INF/layouts/layouts.xml
                
                /WEB-INF/views/**/views.xml
            
        
    
Ở trên tất cả các controller khi trả về view name thì spring sẽ hiển thị view là tiles, các định nghĩa của tiles sẽ nằm trong các file views.xml trong thư mục /WEB-INF/views/ (kể cả thư mục con) và layout để hiển thị tham chiếu từ file layouts.xml trong thư mục /WEB-INF/layouts/
layouts.xml

	
		
		
		
		
		
	
	

để định nghĩa cho template ta chỉ cần put attribute cần đưa vào layout, ví dụ ở đây, template thì header, menu, footer là cố định, còn title và content thì được truyền vào (định nghĩa trong views.xml) views.xml

    
        
        
    
    
        
        
    

Mỗi trang cần áp dụng template thì ta sẽ định nghĩa trong views.xml. trong ví dụ thì ta định nghĩa cho màn create product và hiển thị danh sách product
Kết quả:

Source code: http://www.mediafire.com/download/dodubbe20yaxz0m/Store_tiles.rar
Thanks & Regard!