Thứ Hai, 8 tháng 9, 2014

Servlet Context

Một trường hợp mà servlet context có thể phát huy tác dụng: Giả sử ứng dụng web của bạn có 2 servlet class, và cả 2 đều phải lấy 1 giá trị từ web.xml, trong trường hợp này ServletContext sẽ rất hữu ích vì tất cả các servlet trong cùng 1 ứng dụng web đều có thể truy cập vào các giá trị ở mức context như thê.

Bạn có thể truy cập vào nó thông qua HttpRequest, như thế này:
ServletContext context = request.getServletContext();


Context Attributes

Giống như session, bạn cũng có thể lưu giá trị vào servlet context như sau:

context.setAttribute("NameOfValue",Value);

và lấy giá trị theo tên như sau:

Object attribute = context.getAttribute("NameOfValue");

ServletContext khác với Session ở chỗ, giá trị lưu ở ServletContext có thể được truy cập bởi tất cả các servlet, giữa các requests và sessions. Điều đó có nghĩa giá trị lưu trong ServletContext có thể được dùng cho tất cả các khách ghé thăm trang web. Còn giá trị lưu trong session thì chỉ có 1 khách duy nhất truy cập được.

How to Use:

Chúng ta sẽ tạo một ứng dụng web đếm số lần trang web được ghé thăm

Đầu tiên, chúng ta sẽ tạo 1 servlet có tên là Page1 như sau (Servlet Page2 tương tự):

public class Page1 extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
           
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet NewServlet</title>");            
            out.println("</head>");
            out.println("<body>");
            
            ServletContext context = request.getServletContext();
            Integer count =  (Integer) context.getAttribute("count");
            ìf(count!=null){
                 count = 1;
            }
            
            count++;
            context.setAttribute("count",count);

            out.println("<h1>Page Views " + count + "</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }
}

Bây giờ, mỗi lần chúng ta refesh Page1 thì count sẽ tăng lên 1. Và nếu chúng ta refresh Page 2 thì count sẽ tăng lên 1 từ giá trị count mới nhất từ Page1. Điều đó có nghĩa là 2 servlet Page1 và Page2 cùng có thể truy cập vào giá trị của count ở mức context của ứng dụng web.

Session In Java Web

Một ví dụ của việc dùng session trong việc phát triển ứng dụng web là đặc điểm shopping cart của các trang web mua hàng. Khi bạn chọn lựa và thêm các item vào giỏ hàng, session sẽ nhớ các lựa chọn của bạn; như vậy shopping cart của bạn sẽ có những sản phẩm mà bạn đã lựa chọn khi bạn check out. Nếu k có session, nếu bạn checkout, cái trang mới mà bạn sắp chuyển hướng đến sẽ không nhận biết được các hoạt động mà bạn đã làm từ những trang trước và giỏ hàng sẽ trống trơn, luôn luôn là như vậy. 

Như vậy, Website sử dụng session để chắc chắn rằng nó sẽ nhận ra bạn khi bạn chuyển trang trong cùng một website hoặc khi bạn refesh trang. 

Các phương thức để quản lý session:

URL Rewriting: các client có thể gửi thông tin đến server bằng cách thêm ID của session vào địa chỉ URL cùng với các requests. Việc này khá gây mệt mỏi vì tự chúng ta phải theo dõi các tham số này trong mỗi response từ server và phải đảm bảo rằng các ID của các session k trùng nhau

Hidden Form Variables: Chúng ta có thể tạo các trường ẩn trong HTML và khi người dùng bắt đầu chuyển hướng, chúng ta có thể gán 1 giá trị duy nhất cho người dùng đó, đồng thời theo dõi được các session. Độ bảo mật khi dùng phương pháp này là không cao bới vì chúng ta rất dễ dàng lấy được giá trị từ những trường ẩn này từ HTML

Ngoài ra, còn có những phương thức khác như Persistent Cookies, Persistent Mechanism hay Servlet APIs.., Trong đó, Servlet APIs được xây dựng dựa trên các phương thức trên

Cách sử dụng Session

Chúng ta sẽ tạo một ứng dụng web nhằm lưu username của người dùng vào session rồi sau đó hiển thị ở trang sau:

Đầu tiên, tạo 1 trang HTML như sau:


Sau khi người dùng nhập username và nhấn Login, Servlet Login sẽ kiểm tra xem username có trong database không

Tiếp theo, chúng ta tạo Servlet Login như sau:

public class Login extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            /* TODO output your page here. You may use following sample code. */
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet Login</title>");
            out.println("</head>");
            out.println("<body>");

            String username = request.getParameter("username");
            if (userList.contains(username)) {
                HttpSession session = request.getSession();
                session.setAttribute("username", username);
                RequestDispatcher rd = request.getRequestDispatcher("Logined");
                rd.forward(request, response);
            }
            out.println("<h1>UserName Mismatch " +"</h1>");

            out.println("</body>");
            out.println("</html>");
        }
    }
    protected List<String> userList = null;

    @Override
    public void init() throws ServletException {
        userList = new LinkedList<>();
        userList.add("Long");
        userList.add("Hoang");
        userList.add("Tuan");

    }
}

Ở trên, chúng ta có 1 mock data là userList được khởi tạo và thêm phần tử ở hàm init().
Ở hàm processRequest(), username được lưu vào 1 session có tên là "username" thông qua session.setAttribute("SessionName", SessionValue) rồi sau đó chuyển hướng trang sang Logined Servlet 

Tại Servlet Logined, giá trị của session có tên là "username" được lấy ra thông qua session.getAttribute("SessionName") và hiển thị trong hàm processRequest:

 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
         
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet Logined</title>");            
            out.println("</head>");
            out.println("<body>");

             HttpSession session = request.getSession();
            String username = (String) session.getAttribute("username");

            out.println("<h1>Hello, " + username + "</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }

Use Request Dispatcher

ĐỀ BÀI:

Implement an application as following:
Depends of the question, GateKeeper will forward request to corresponding Answers.

1. Tạo trang HTML:
Chúng ta tạo 1 trang index.HTML đơn giản như sau:

GateKeeper là 1 servlet, có nhiệm vụ nhận thông tin từ trang index.html và chuyển hướng tới các servlets khác tương ứng với câu hỏi từ input có name là question.

2. Tạo Servlet GateKeeper

Tạo 1 List số để so sánh với input của người dùng:

                private List<String> answerCodes = null;
               @Override
                public void init() throws ServletException {
                      answerCodes = new LinkedList<>();
                      answerCodes.add("1");
                      answerCodes.add("2");
                      answerCodes.add("3");
                }

Xử lý hàm processRequest của Servlet này như sau:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            /* TODO output your page here. You may use following sample code. */
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet GateKeeper</title>");            
            out.println("</head>");
            out.println("<body>");

            String question = request.getParameter("question");
            List<String> collect = answerCodes.stream().filter(s -> question.contains(s)).collect(Collectors.toList());
            
            if(collect!= null){
                RequestDispatcher rd = request.getRequestDispatcher("Answer" +collect.get(0));
                rd.forward(request, response);
            }
            

            out.println("<h1>No corresponding answer " + "</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }

Hàm "filer" ở trên sẽ lọc các phần tử thỏa mãn điều kiện input của người dùng chứa mã câu hỏi nào (answerCode) thì sẽ trả về mã câu hỏi đó. Ví dụ, nếu input của người dùng có giá trị là "a1" thì biến collect sẽ chứa answerCode là 1. Còn nếu giá trị input của người dùng k thỏa mãn điều kiện trên thì sẽ hiện thông báo "No corresponding answer".

Trường hợp collect != null, GateKeeper sẽ chuyển hướng sang những servlet tương ứng.Ví dụ Servlet Answer1 như sau:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            /* TODO output your page here. You may use following sample code. */
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet Answer1</title>");          
            out.println("</head>");
            out.println("<body>");
                     
            out.println("<h1>Question1" + "</h1>");
            out.println("<h1>Question1 answered"+"</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }

Thứ Sáu, 5 tháng 9, 2014

Servlet Initialization Parameters

Chúng ta có thể tùy chỉnh các tham số khởi tạo của servlet ngay trước khi chúng được khởi tạo và đưa vào phục vụ. Việc xác định các tham số khởi tạo này cho phép servlet có thể thực hiện được các nhiệm vụ mà chỉ cần làm một lần duy nhất bằng cách override phương thức init() của Servlet interface.

Những tham số khởi tạo được truyền vào servlet từ file web.xml. Chúng chỉ được sử dụng duy nhất bởi chính servlet đó. Sau đây là cách chúng ta config web.xml để khởi tạo tham số:

<servlet>
        <servlet-name>NewServlet</servlet-name> 
        <servlet-class>NewServlet</servlet-class>
        <init-param> 
             <param-name>myParam</param-name> 
             <param-value>paramValue</param-value> 
        </init-param>
</servlet>



Sau đây là cách chúng ta lấy các tham số khởi tạo ra từ trong servlet - cụ thể là trong phương thức init():

public class NewServlet extends HttpServlet {
    protected String myParam = null; 
   @Override
    public void init(ServletConfig servletConfig) throws ServletException{ 
       this.myParam = servletConfig.getInitParameter("myParam"); 
    }    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            /* TODO output your page here. You may use following sample code. */
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet NewServlet</title>");          
            out.println("</head>");
            out.println("<body>");

            out.println("<h1>Initial Value Is " + myParam  + "</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }
}
Phương thức init(ServletConfig servletConfig) được gọi khi servlet container tải servlet lần đầu tiên. Không ai có thể truy cập vào servlet cho đến khi nó hoàn toàn được tải lên servlet container. Sau khi init() ở trên được gọi thành công, thì các tham số khởi tạo đã được lấy ra từ file web.xml thông qua servletConfig.getInitParameter("myParam") và sau đó output ra màn hình dưới dạng HTML
( out.println("<h1>Initial Value Is " + myParam  + "</h1>");)




           

Thứ Năm, 4 tháng 9, 2014

Develop A Web App

Để tạo một ứng dụng web bằng java, chúng ta nên dùng Netbeans 8.0 bản có Java EE để có thể tạo được ứng dụng web

Sau khi cài Netbeans 8.0, chạy chương trình. Các bước để tạo 1 ứng dụng web:

I. Create Java Web

1. Tạo mới một Web Application
Nhấn vào File >> New Project >>chọn Java Web >> Web Application, như hình:


Nhấn Next để tiếp tục

2. Chọn Name và Location

Chọn Name và Location cho project web vừa tạo


Nhấn Next để tiếp tục

3. Tùy chọn Server và Settings

Chọn server là Apache Tomcat - kèm theo NetBeans 8.0. Nếu chưa có thì phải download về và cài đặt bản phù hợp với Netbeans ver bạn đang dùng


Nhấn Next để tiếp tục

4. Kết thúc

Tiếp theo là chọn Framework, các bạn có thể tạm thời bỏ qua bước này. Nhấn Next để hoàn thành việc tạo 1 web app.

II. Create Servlet to serve Client

1. Tạo trang HTML(có sẵn mặc định là trang index.html trong project vừa tạo ở trên)
2. Tạo Servlet

Click  Source Packages folder >> chuột phải vào default package >> New >> Servlet và được kết quả:


Đặt tên cho Servlet rồi nhần Next >> tick vào ô Add Information to deployment descriptor >> Finish

Như vậy là chúng ta đã có 1 Web App với Server hoàn chỉnh.

Test Server bằng cách thêm markup cho index.html như sau:


Sau đó, chạy chương trình và nhấn vào link "new Link", kết quả hiển thị như sau thì có nghĩa server đã hoạt động:


Servlet LifeCycle

Servlet có một vòng đời nhất định và được quản lý bởi servlet container, bao gồm các giai đoạn  
  1. Tải Servlet Class.
  2. Tạo Instance of Servlet.
  3. Gọi phương thức init().
  4. Gọi phương thức service().
  5. Gọi phương thức destroy().
Giai đoạn 1, 2 and 3 chỉ được thực hiện 1 lần duy nhất khi servlet lần đầu tiên được tải.

Giai đoạn 4 được thực hiện nhiều lần - 1 lần/1 HTTP request.
Giai đoạn 5 được thực hiện khi servlet container dỡ bỏ (unload)servlet.
Mỗi giai đoạn được mô tả như sau

Tải Servlet Class

Trước khi một servlet có thể được gọi thì servlet container phải tải servlet class. Theo mặc định thì servlet sẽ không được tải khi chưa nhận được request đầu tiên nào. Tuy nhiên chúng ta có thể bắt container load servlet theo tùy chỉnh của chúng ta.

Tạo Instance của Servlet

Khi servlet class được tải, servlet container tạo 1 instance của servlet.
Bình thường,chỉ 1 isntance duy nhất của servlet được tạo, và những request đồng thời cùng lúc tới servlet sẽ được xử lý ở cùng 1 instance của servlet.

Gọi phương thức Servlets init()

Khi servlet instance được tạo, phương thức init() sẽ được gọi, cho phép servlet được khởi tạo trước khi request đầu tiền được xử lý.
Chúng ta có thể xác định tham số cho phương thức init() của servlet trong web.xml file. Xem web.xml Servlet Configuration.

Gọi phương thức Servlets service()

Đối với mỗi request mà servlet nhận được, nó sẽ gọi phương thức service(). Đối với HttpServlet subclasses, phương thức doGet(), doPost() etc sẽ được gọi.
Đến khi nào servlet còn hoạt động trong servlet container thì phương thức service() còn có thể được gọi. Vì thế giai đoạn này có thể được thực hiện nhiều lần

Gọi phương thức Servlets destroy()

Khi servlet container gỡ bỏ 1 servlet, phương thức destroy() của servlet sẽ được gọi. Bước này chỉ được thực hiện 1 lần vì 1 servlet chỉ được gỡ bỏ 1 lần duy nhất.
Một servlet sẽ được gỡ bỏ bởi container nếu container dừng hoạt động hoặc khi container tải lại toàn bộ ứng dụng web khi ứng dụng đang chạy.

Basic of HTTP


Hypertext Transfer Protocol (HTTP) là một giao thức không lưu trạng thái (stateless) và không giữ kết nối (connectionless),  nó là nền tảng của web và nhận trách nhiệm việc giao tiếp và trao đổi thông tin trong thế giới web chủ yếu thông qua TCP/IP

HTTP hoạt động như một giao thức request-response trong mô hình client-server. Ví dụ như một trình duyệt web có thể là client và một ứng dụng chạy trên một máy tính host trang web đó có thể là server. Các client gửi một  HTTP request đến server. Các server, cung cấp các nguồn tài nguyên như các tập tin HTML và nội dung khác, hoặc thực hiện các chức năng khác thay mặt cho client, trả về một response cho các client.



Giao thức HTTP là phi trạng thái (stateless) là do server không cần phải theo dõi trạng thái của các request khác nhau từ client, không phải là nó không thể làm như vậy, nó có thể nếu muốn. Điều này giúp đơn giản hoá giàng buộc giữa client và server, và trong nhiều trường hợp giảm thiểu lượng dữ liệu cần được chuyển giao. Nếu các server được yêu cầu để duy trì trạng thái của các request từ client thì cơ cấu phát hành và đáp ứng lại các request sẽ phức tạp hơn. Đối với các ứng dụng web cần lưu lại trạng thái của người dùng thì có thể sử dụng HTTP persistent connection hoặc HTTP cookie

Ngoài ra, HTTP cũng không giữ kết nối (connectionless). Lý do chính là do khả năng mở rộng (scalibility). Duy trì một kết nối active cho mỗi client trở nên rất tốn kém tài nguyên. Hơn nữa, ý tưởng ban đầu của việc hình thành HTTP thể hiện dưới dạng "Hãy gửi cho tôi tài liệu X" rồi sau đó "Tài liệu X của bạn đây" rồi kết thúc- rất đơn giản. Vì thế việc duy trì kết nối trở nên không cần thiết.