Hiển thị các bài đăng có nhãn spring mvc. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn spring mvc. Hiển thị tất cả bài đăng

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

Conflict giữa Apache basic authentication và spring security

Nếu Tomcat có sử dụng Apache basic authentication để xác thực. nếu ứng dụng sử dụng tomcat trên, và có tích hợp với spring security thì sẽ có conflict giữa 2 dạng xác thực này. Mình đã gặp lỗi này và phải mất 1 tiếng chạy đi hỏi lại network, rồi test lại chương trình. chỉ cần thay tag cấu hình <http> cho spring security thì sẽ không config.
thay

<http auto-config="true">
 <form-login login-page="/login" default-target-url="/index"
 authentication-failure-url="/failure"  />
 <logout logout-success-url="/login" />
 <access-denied-handler error-page="/denied"/>
</http>
bằng cách bỏ auto-config đi


<http>
 <form-login login-page="/login" default-target-url="/index"
 authentication-failure-url="/failure"  />
 <logout logout-success-url="/login" />
 <access-denied-handler error-page="/denied"/>
</http>

Tham khảo tại đây: http://docs.spring.io/autorepo/docs/spring-security/3.1.4.RELEASE/reference/ns-config.html

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

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!

Thứ Hai, 30 tháng 12, 2013

Theme trong Spring MVC

Một ứng dụng web đôi khi chúng ta cần thay đổi lại theme của giao diện, ví dụ như color, image, style..
Spring hỗ trợ thay đổi giao diện bằng interface org.springframework.ui.context.ThemeSource và load theme được định nghĩa trong resources bằng org.springframework.ui.context.support.ResourceBundleThemeSource
trong ví dụ này ta có 2 theme là default và blue, hiển thị sẽ như sau:
default


blue
và 2 flie css 
blue.css
body{
background-color:#5cf;
}
default.css
body{
 background-color:#fff;
}

Ta sẽ tạo 2 file properties trong thư mục scr/main/resources/themes
blue.properties
theme=resources/css/themes/blue.css
default.properties
theme=resources/css/themes/default.css
Các file này sẽ chỉ ra style nào được áp dụng qua tham số key = theme
Điều quan trọng nhất là cấu hình cho spring xử lý như mong muốn của ta
vào file /WEB-INF/spring/appServlet/servlet-context.xml
thêm vào đoạn config sau:

   
  
   
    
  
 
 
 
  
   
  
  
 
Trong đoạn config

   
  
   
    
   
ta khai báo bean của lớp org.springframework.web.servlet.theme.ThemeChangeInterceptor để có thể xử lý theme, khi người dụng truyền vào paramerer có name là "theme" bean "themeSource"
 
 
 
   
sẽ load file resource từ forder themes với basenamePrefix = ""
Bạn có thể sửa lại tên file theo prefix nào đó ví dụ: xxx_blue.properties thì bạn sẽ khai báo là basenamePrefix = "xxx" Bean "themeResolver"
   
  
  
sẽ lưu theme hiện tại vào cookie, ngoài ra khai báo theme default là "default" (tùy chọn)
Cuối cùng trong file jsp ta sẽ cấu hình như sau:
createProduct.jsp:
diepviends blog
" type="text/css"/>

diepviends blog
" type="text/css"/>

Source code:
https://www.mediafire.com/?gz4eq9u94pfqt03

Thks & rgds!

i18n trong Spring MVC

Trong bài này ta sẽ xây dựng website đa ngôn ngữ i18n (Internationalization)
Cấu trúc thư mục sẽ như sau:

trong thư mục /WEB-INF/i18n ta sẽ tạo 2 file properties application.properties và application_vi.properties lưu trữ các label cho ngôn ngữ mặc định  và ngôn ngữ tiếng việt ( ngôn ngữ mặc định đây là tùy chọn, cấu hình trong servlet-context.xml)
file application_vi.properties
file application.properties

và sửa lại view để hỗ trợ hiển thị theo ngôn ngữ tùy chọn
createProduct.jsp
listProduct.jsp

ở đây ta dùng <spring:message code="application.name" /> được hỗ trợ bởi spring, khai báo taglib là <%@taglib uri="http://www.springframework.org/tags" prefix="spring"%> để lấy message theo code được khai báo trong properties
Bây giờ sẽ cấu hình để ứng dụng có thể load các label theo key mà ta đã định nghĩa trong file properties
mở file config: /WEB-INF/spring/appServlet/servlet-context.xml
thêm vào đoạn sau:
 
 
  
 
 
 
  
 
 
  
  
 
 

bean localeChangeInterceptor sẽ xử lý yêu cầu về load resource theo ngôn ngữ được lựa chọn, dựa vào parameter là "lang"
bean localeResolver sẽ lưu ngôn ngữ hiện tại vào cookie của trình duyệt, ngôn ngữ mặc định đây là "en" (tùy chọn)
và bean messageSource sẽ load file properties được định nghĩa trong WEB-INF/i18n/, các file được load là application*.properties.
sau khi Run As project
vào theo các url sau để xem kết quả
http://localhost:8080/store/product/create?lang=en
http://localhost:8080/store/product/create?lang=vi
source code
https://www.mediafire.com/?skzzpktm4c5pmwm
Thks & rgds!

Thứ Năm, 26 tháng 12, 2013

Xử lý form trong Spring MVC

Trong phần này ta sẽ làm ví dụ xử lý dữ liệu lấy từ form ở trang JSP.
File->new->Spring project->Spring MVC Project
cấu trúc thư mục sẽ như sau:

Nội dung:
Sử dụng domain sau để lưu trữ thông tin của 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;

 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;
 }
}


Chương trình sẽ lấy dữ liệu khi người dùng nhập vào

 và in ra danh sách


dữ liệu nhập vào sẽ được validate như hình sau

Đầu tiên ta xây dựng file properties để lưu trữ thông báo cho chương trình.
file product-messages.properties sẽ được tạo ra ở thư mục src/main/resources

các parameter được tryền vào theo các vị trí {0} {1}...
Để spring đọc được file resources này ta định nghĩa thêm 1 bean  là thể hiện của lớp org.springframework.context.support.ReloadableResourceBundleMessageSource để đọc messages.
vào file WEB-INF/spring/appServlet/servlet-context.xml thêm đoạn sau:

  
 

Toàn bộ file servlet-context.xml sẽ như thế này:


 
 
 
 

 
 

 
 
  
  
 
 
 
 
 
  
 
 



Xong phần cấu hình, giờ sẽ xây dựng một lớp ProductValidator để valid dữ liệu từ người dùng. Vì spring đã hỗ trợ validate trong interface Validator nên class của ta chỉ việc implements giao diện đó và triển khai phương thức validate() của Validator interface.
package vn.ds.store.validators;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import vn.ds.store.domains.Product;

public class ProductValidator implements Validator {

 @Override
 public boolean supports(Class clazz) {

  return Product.class.isAssignableFrom(clazz);
 }

 @Override
 public void validate(Object target, Errors errors) {
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name",
    "msg.required", new Object[] { "name" });
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "price",
    "msg.required", new Object[] { "price" });
  Product product = (Product) target;
  String name = product.getName();
  int max = 6;
  if (!name.isEmpty() && name.length() > max)
   errors.rejectValue("name", "msg.maxlength", new Object[] { "name",
     max }, "");
  if (!isNumber(product.getPrice().trim()))
   errors.rejectValue("price", "msg.number", new Object[] { "price",
     max }, "");
 }

 public boolean isNumber(String s) {
  for (int i = 0; i < s.length(); i++) {
   if (!Character.isDigit(s.charAt(i)))
    return false;
  }
  return true;
 }

}


Phương thức
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name",
    "msg.required", new Object[] { "name" });
sẽ kiểm tra xem trường "name" có emty hay có space không, nếu có sẽ add thêm một message vào đối tượng errors, nội dung msg sẽ được lấy theo id của msg trong resources là "msg.required" và truyền vào một parameter cho msg đó là một mảng Object có 1 phần tử là "name". Tương tự phương thức
errors.rejectValue("price", "msg.number", new Object[] { "price",
     max }, "");
cũng sẽ add thêm một msg của trường "price" vào errors theo msg là "msg.number" và set vào 2 parameter là một biến String "price" và một biến Integer max
Controller
package vn.ds.store.controllers;

import java.util.ArrayList;

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 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) {
  validator.validate(product, errors);
  if (errors.hasErrors()) {
   return "createProduct";
  }
  ArrayList lst = new ArrayList();
  Product p = new Product();
  p.setName("product 1");
  p.setPrice("100");
  lst.add(p);
  lst.add(product);
  model.addAttribute("products", lst);
  return "listProduct";
 }
}


Ở đây Phương thức GET của url "/product/create" sẽ được xử lý bởi hàm doGet(). hàm này sẽ tạo mới một đối tượng Product và add vào model. sau đó trả về một view có tên là "createProduct". view này là view jsp được định nghĩa trong file servlet-context.xml. vì ta không định nghĩa cụ thể nên spring sẽ xem id của view theo tên file jsp. Phương thức POST của url "/product/save" sẽ xử lý khi người dụng submit form trong method doPost()
Đầu tiên sẽ validate dữ liệu theo đối tượng ProductValidator. nếu có lỗi sẽ trả về view "createProduct" là trang nhập dữ liệu
Nếu không có lỗi sẽ thực hiện add dữ liệu vào model và gửi xuống view "listProduct".
JSP
file createProduct.jsp trong thư mục WEB-INF/views sẽ như sau:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>




Insert title here



 
  
create
Name
Price
 

và view hiển thị danh sách listProduct.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>   




Insert title here



 
List of products
Name Price
${p.name} ${p.price}

Source code theo link http://www.mediafire.com/download/vki3lvwpsqtpam8/Store_handling_form.rar Thanks & Rgds!!!

Thứ Tư, 25 tháng 12, 2013

Hướng dẫn sử dụng Spring Tool Suice (STS)

Spring Tool Suice (STS) là một plugin cho Eclipse hỗ trợ dev phát triển các project dựa trên Spring framework
http://spring.io/tools/sts
Bài viết này sẽ hướng dẫn cách sử dụng STS
Trên thanh công cụ của Eclipse->Help->EclipseMarketplace
Gõ vào ô tìm kiếm với từ khóa STS
Chọn STS phù hợp với phiên bản Eclipse-> Install


Sau khi eclipse hoàn tất cài đặt và khởi động lại
cần phải bỏ valid derived query để tránh các cảnh báo lỗi không cần thiết
Window->Preferences->Spring.
ở tab Project validators->Data validator và bỏ check  ở Invalid Derived Query-> OK

Create một project Spring web MVC

File->New->Spring Project->Spring MVC Project

Nhập tên package và Finish



STS sẽ tự động tạo một project mẫu với một controller Home

Nếu Project bị lỗi, là do version của spring đó không còn maven không hỗ trợ để load thư viện về.
để sửa bạn vào file pom.xml. chọn properties của spring và thay bằng version khác (có thể tham khảo tại http://mvnrepository.com/artifact/org.springframework)


Sau đó save lại, và chọn Project->clean.
bây giờ click phải chuột vào Store->Run As
và xem kết quả!

Bây giờ hãy xem lại example vừa được tạo ra
cấu trúc thư mục sẽ như thế này

Một ứng dụng spring MVC sẽ theo đúng mô hình MVC chuẩn, ta quan tâm đến các file sau: HomeController.java, web.xml, servlet-context.xml

HomeController.java
package vn.ds.store;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
 
 private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
 
 /**
  * Simply selects the home view to render by returning its name.
  */
 @RequestMapping(value = "/", method = RequestMethod.GET)
 public String home(Locale locale, Model model) {
  logger.info("Welcome home! The client locale is {}.", locale);
  
  Date date = new Date();
  DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
  
  String formattedDate = dateFormat.format(date);
  
  model.addAttribute("serverTime", formattedDate );
  
  return "home";
 }
 
}


Controller này sẽ xử lý request cho ull "/"  và trả về một view có tên là "home"

web.xml


 
 
  contextConfigLocation
  /WEB-INF/spring/root-context.xml
 
 
 
 
  org.springframework.web.context.ContextLoaderListener
 

 
 
  appServlet
  org.springframework.web.servlet.DispatcherServlet
  
   contextConfigLocation
   /WEB-INF/spring/appServlet/servlet-context.xml
  
  1
 
  
 
  appServlet
  /
 
Ứng dụng Spring sẽ được xoay quanh một servlet trung tâm là DispatcherServlet, các request khi yêu cầu đến ứng dụng đều được servlet này xử lý sau đó lựa chọn controller xử lý và trả về model and view nào phù hợp
Các request sẽ được xử lý theo url-mapping là "/"
ở đây bạn có thể sửa url để DispatcherServlet xử lý  như .html, .do, .xxx ....
Servlet-context.xml


 
 
 
 

 
 

 
 
  
  
 
 
 
 
 
 


Dòng <annotation-driven /> sẽ cho phép sử dụng các @notation, đây là một đặc điểm của spring kể từ spring 3 trở đi
các phương thức GET yêu cầu resources(image, js, css..) sẽ được khai báo bởi dòng
<resources mapping="/resources/**" location="/resources/" />
Khai báo viewResolver là jsp ở dòng
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
Có thể khai báo nhiều viewResolver khác như pdf, excel...
Cuối cùng dòng
<context:component-scan base-package="vn.ds.store" />
sẽ cho phép quét các class được khai báo là controller (bởi anotation @Controller) ở trong package được chỉ ra, ở đây là vn.ds.store
Tương tự bạn có thể tạo ra nhiều controller khác  để xử lý các nghiệp vụ khác nhau trong package đó, và tạo file jsp trong /WEB-INF/views/ để hiển thị.

Thks & Rgds!

Thứ Năm, 26 tháng 9, 2013

Export Excel, PDF trong SpringMVC

Xuất file excel ta dùng thư viện apache poi: http://poi.apache.org/Xuất file pdf ta dùng thư viện itextpdf: http://itextpdf.com/

Ví dụ này ta sẽ xuất ra dưới dạng bảng thống kê, tức là có title, có các header cho các column và data cho bảng đó, như vậy, ta sẽ xây dựng 2 lớp builder nhận vào các đối là
Title: 1 chuỗi String
header: 1 Vector
data: 1 Vector
Đây là lớp ExcelBuilder để export ra file excel:

package vn.diepviends.util;

import java.util.Map;
import java.util.Vector;

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

import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.springframework.web.servlet.view.document.AbstractExcelView;

public class ExcelBuilder extends AbstractExcelView {
 @Override
 protected void buildExcelDocument(Map model,
   HSSFWorkbook workbook, HttpServletRequest request,
   HttpServletResponse response) throws Exception {
  // get data
  Vector vHeader = (Vector) model.get("header");
  Vector vData = (Vector) model.get("data");
  String sTitle = model.get("title").toString();
  // create a excel sheet
  HSSFSheet sheet = workbook.createSheet(sTitle);
  sheet.setDefaultColumnWidth(30);
  // create style for header cells
  CellStyle style = workbook.createCellStyle();
  Font font = workbook.createFont();
  font.setFontName("Times New Roman");
  style.setFillForegroundColor(HSSFColor.BLUE.index);
  style.setFillPattern(CellStyle.SOLID_FOREGROUND);
  font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
  font.setColor(HSSFColor.WHITE.index);
  style.setFont(font);
  // create header row
  HSSFRow title = sheet.createRow(0);
  title.createCell(0).setCellValue(sTitle);
  HSSFRow header = sheet.createRow(1);  
  for (int i = 0; i < vHeader.size(); i++) {
   header.createCell(i).setCellValue(vHeader.get(i).toString());
   header.getCell(i).setCellStyle(style);
  }
  // fill data
  int r = 2;
  for (int i = 0; i < vData.size(); i++) {
   Vector v = (Vector) vData.get(i);
   HSSFRow row = sheet.createRow(r++);
   for (int j = 0; j < v.size(); j++)
    row.createCell(j).setCellValue(v.get(j).toString());
  }
 }
}

Controller ta sẽ viết như sau:
@RequestMapping("/registerReport/export2excel")
 public String exportExcel(@RequestParam(value = "from") String from,
   @RequestParam(value = "to") String to, Model model) {
  ProvisionReportDAO dao = new ProvisionReportDAO();
  String title = "Register Report";
  Vector header = new Vector();
  Vector data = new Vector();
  ArrayList list = dao.getByDate(from, to);  
  header.add("Date");
  header.add("Quantity");
  header.add("Provision Type");
  header.add("provision Code");
  for(ProvisionReport it : list){
   Vector v = new Vector();
   v.add(it.getDate());
   v.add(it.getQuantity());
   v.add(it.getType());
   v.add(it.getCode());
   data.add(v);
  }  
  model.addAttribute("title", title);
  model.addAttribute("header", header);  
  model.addAttribute("data",data); 
  return "excelView";
 }

Với PDF thì ta phải xây dựng một lớp Abstract trung gian:
package vn.diepviends.util;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Map;

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

import org.springframework.web.servlet.view.AbstractView;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;

public abstract class AbstractITextPdfView extends AbstractView {

 public AbstractITextPdfView() {
  setContentType("application/pdf");
 }

 @Override
 protected boolean generatesDownloadContent() {
  return true;
 }
  
 @Override
 protected void renderMergedOutputModel(Map model,
   HttpServletRequest request, HttpServletResponse response) throws Exception {
  // IE workaround: write into byte array first.
  ByteArrayOutputStream baos = createTemporaryOutputStream();

  // Apply preferences and build metadata.
  Document document = newDocument();
  PdfWriter writer = newWriter(document, baos);
  prepareWriter(model, writer, request);
  buildPdfMetadata(model, document, request);

  // Build PDF document.
  document.open();
  buildPdfDocument(model, document, writer, request, response);
  document.close();

  // Flush to HTTP response.
  writeToResponse(response, baos);
 }

 protected Document newDocument() {
  return new Document(PageSize.A4);
 }
 
 protected PdfWriter newWriter(Document document, OutputStream os) throws DocumentException {
  return PdfWriter.getInstance(document, os);
 }
 
 protected void prepareWriter(Map model, PdfWriter writer, HttpServletRequest request)
   throws DocumentException {

  writer.setViewerPreferences(getViewerPreferences());
 }
 
 protected int getViewerPreferences() {
  return PdfWriter.ALLOW_PRINTING | PdfWriter.PageLayoutSinglePage;
 }
 
 protected void buildPdfMetadata(Map model, Document document, HttpServletRequest request) {
 }
 
 protected abstract void buildPdfDocument(Map model, Document document, PdfWriter writer,
   HttpServletRequest request, HttpServletResponse response) throws Exception; 
}

Lớp PDFBuilder extends lớp Abstract trên:
package vn.diepviends.util;

import java.util.Map;
import java.util.Vector;

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

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

public class PDFBuilder extends AbstractITextPdfView {

 @Override
 protected void buildPdfDocument(Map model, Document doc,
   PdfWriter writer, HttpServletRequest request,
   HttpServletResponse response) throws Exception {
  // get data
  Vector vHeader = (Vector) model.get("header");
  Vector vData = (Vector) model.get("data");
  String sTitle = model.get("title").toString();
  
  doc.add(new Paragraph(sTitle));
  PdfPTable table = new PdfPTable(vHeader.size());
  table.setWidthPercentage(100.0f); 
  table.setSpacingBefore(10);
  // define font for table header row
  Font font = FontFactory.getFont(FontFactory.HELVETICA);
  font.setColor(BaseColor.WHITE);

  // define table header cell
  PdfPCell cell = new PdfPCell();
  cell.setBackgroundColor(BaseColor.BLUE);
  cell.setPadding(5);
  for (int i = 0; i < vHeader.size(); i++) {
   // write table header
   cell.setPhrase(new Phrase(vHeader.get(i).toString(), font));
   table.addCell(cell);
  }  
  // write table row data
  int x = vData.size();
  int y = vHeader.size();
  for(int i = 0; i


Controller ta sẽ viết như sau:
@RequestMapping("/registerReport/export2pdf")
 public String exportPdf(@RequestParam(value = "from") String from,
   @RequestParam(value = "to") String to, Model model) {
  ProvisionReportDAO dao = new ProvisionReportDAO();
  String title = "Register Report";
  Vector header = new Vector();
  Vector data = new Vector();
  ArrayList list = dao.getByDate(from, to);  
  header.add("Date");
  header.add("Quantity");
  header.add("Provision Type");
  header.add("provision Code");
  for(ProvisionReport it : list){
   Vector v = new Vector();
   v.add(it.getDate());
   v.add(it.getQuantity());
   v.add(it.getType());
   v.add(it.getCode());
   data.add(v);
  }  
  model.addAttribute("title", title);
  model.addAttribute("header", header);  
  model.addAttribute("data",data); 
  return "pdfView";
 }

Định nghĩa các view để hiển thị ra excel và pdf

     
    
     


Trong dispatcher của spring ta gọi view.xml vào:

        
 
 
  
  
         
        
   
   
    



và đây là kết quả: