Spring MVC AJAX Hello World Example - Kiến thức cơ bản HTTP và AJAX

Khi tìm hiểu về giao thức HTTP mình có đọc 1 số bài hướng dẫn trả lời phỏng vấn về giao thức HTTP như:
Phương thức POST bảo mật hơn GET vì dữ liệu được gửi ngầm bằng mắt thường không thể nhìn thấy được
Phương thức GET luôn luôn nhanh hơn POST vì dữ liệu gửi đi được Browser giữ lại trong cache
Phương thức GET dữ liệu được gửi tường minh, chúng ta có thể thấy trên URL nên nó không bảo mật.
Các câu trả lời ở bên trên chưa chính xác là do bạn chưa hiểu đúng về giao thức HTTP


**Trong bài hướng dẫn này mình sẽ nói đến các vấn đề sau**
1) Các khái niệm cơ bản về giao thức HTTP (GET, POST)
2) Tạo 1 web application sử dụng Spring MVC với AJAX

Giao thức HTTP( Hyper Text Transfer Protocol) là gì ?
HTTP là giao thức quy ước chung để cho 2 đối tượng A và B có thể giao thông ( giao tiếp ) với nhau. Cụ thể là giao tiếp với nhau bằng 1 định dạng sử dụng chữ (text)

Ta đã biết phép căn bản của phần mềm là 2 phép đọc (read) và ghi (write) dữ liệu (Phần mềm viết ra là để xử lý dữ liệu) - phép ghi còn tách ra làm 3 phép thêm, sửa, xóa. Khi người ta thiết kế ra giao thức HTTP cũng xoay quanh các phép căn bản này của phần mềm. Từ 4 phép căn bản này sẽ tạo ra 7 HTTP method:

  • 4 phép đại diện cho đọc (read):
  1. GET
  2. Trace: đọc lỗi
  3. Option
  4. Head: đọc phần header
  • 3 phép đại diện cho ghi (write):
  1. PUT
  2. POST
  3. DELETE

Nhưng trong quá trình làm việc chúng ta gần như chỉ sử dụng 1 phép đại diện cho đọc là GET, 1 phép đại diện cho ghi là POST. Từ đây dẫn đến sự khác nhau giữa GET và POST:

  1. Ví dụ A muốn gửi 1 thông điệp (message) rằng A muốn đọc dữ liệu (GET) của B, như vậy A không cần mang dữ liệu lên B. Nhưng khi A muốn gửi (POST) 1 bức ảnh đến B, A phải mang dữ liệu lên B. Như vậy GET đại diện cho phép đọc sẽ không có phần body mà chỉ có header, còn POST đại diện cho phép ghi sẽ có phần body (đưa dữ liệu vào body)
  2. Sự khác nhau giữa cấu trúc của GET và POST sẽ ảnh hưởng đến điểm mạnh điểm yếu của POST và GET.
  • GET sẽ nhanh hơn POST: GET sẽ đi nhanh hơn POST trong môi trường mạng vì nó k có body. Phần server khi xử lý message này sẽ nhanh hơn vì GET chỉ có header (khi nói đến nhanh ta phải nhắc đến 2 khía cạnh: traffic và performance)
  • Điểm mạnh của POST là đưa được data lên. Nếu muốn đưa 1 đoạn video, 1 bức ảnh GET sẽ k thể nào làm được

    => Nhưng vì GET đi nhanh hơn nên người ta có xu hướng dùng GET nhiều hơn, thế nên những dữ liệu mà mang lên server đủ nhỏ thì người ta có thể chuyển dữ liệu theo đường GET
  • GET và POST đều có tính bảo mật như nhau, vì đối với GET ta có thể sử dụng kỹ thuật ajax để parametter k hiển thị lên trên url

**Tạo 1 project sử dụng Spring MVC + Ajax bằng maven, server chạy bằng jetty **

Ajax là gì ?
Ajax là một khái niệm có thể mới lạ với những bạn newbie mới học lập trình web nên đôi lúc các bạn nghĩ nó là một ngôn ngữ lập trình mới. Nhưng thực tế không như vậy, ajax là một kỹ thuật viết tắt của chữ AJAX = Asynchronous JavaScript and XML, đây là một công nghệ giúp chung ta tạo ra những Web động mà hoàn toàn không reload lại trang nên rất mượt và đẹp. Đối với công nghệ web hiện nay thì ajax không thể thiếu, nó là một phần làm nên sự sinh động cho website

Các công nghệ sẽ sử dụng trong phần hg dẫn này:

  1. Spring 4.2.2.RELEASE
  2. Jackson 2.6.3
  3. Logback 1.1.3
  4. jQuery 1.10.2
  5. Maven 3
  6. JDK 1.8
  7. Tomcat 8 or Jetty 9
  8. Eclipse 4.5
  9. Boostrap 3

**Cấu trúc project **

Screen Shot 2016-04-18 at 10.27.43 PM.png

**1)Project dependency: **

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.viblo</groupId>
	<artifactId>viblo-spring-learn-ajax</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>viblo-spring-learn-ajax Maven Webapp</name>
	<url>http://maven.apache.org</url>

	<properties>
		<jdk.version>1.8</jdk.version>
		<spring.version>4.2.2.RELEASE</spring.version>
		<jackson.version>2.6.3</jackson.version>
		<logback.version>1.1.3</logback.version>
		<jcl.slf4j.version>1.7.12</jcl.slf4j.version>
		<jstl.version>1.2</jstl.version>
		<servletapi.version>3.1.0</servletapi.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<!-- Need this for json to/from object -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>${jackson.version}</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>

		<!-- JSTL for views -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>

		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${jcl.slf4j.version}</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
		</dependency>

		<!-- compile only, runtime container will provide this -->
		<!-- Need this for config annotation -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servletapi.version}</version>
			<scope>provided</scope>
		</dependency>

	</dependencies>

	<build>
		<finalName>viblo-spring-learn-ajax</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.12.4</version>
				<configuration>
					<skipTests>true</skipTests>
					<argLine>-Xmx2524m</argLine>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
					<fork>true</fork>
					<compilerArgs>
						<arg>-XDignore.symbol.file</arg>
					</compilerArgs>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.eclipse.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>9.3.0.M1</version>
				<configuration>
					<jvmArgs>-Xmx2048m -Xms1536m
						-XX:PermSize=128m -XX:MaxPermSize=512m</jvmArgs>
					<reload>manual</reload>
					<systemProperties>
						<systemProperty>
							<name>lib</name>
							<value>${basedir}/target/viblo-spring-learn-ajax/WEB-INF/lib</value>
						</systemProperty>
					</systemProperties>
					<scanIntervalSeconds>3</scanIntervalSeconds>
					<connectors>
						<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
							<port>8080</port>
							<maxIdleTime>60000</maxIdleTime>
						</connector>
					</connectors>
					<contextPath>/</contextPath>
					<webAppSourceDirectory>${basedir}/src/main/webapp</webAppSourceDirectory>
					<webXml>${basedir}/src/main/webapp/WEB-INF/web.xml</webXml>
					<classesDirectory>${basedir}/target/classes</classesDirectory>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

2)AjaxController AjaxController sẽ xử lý các ajax request từ phía client như thêm, hoặc tìm kiếm ! Sau đó trả về kết quả dưới dạng json cho client.

@Controller
@RequestMapping("/home")
public class AjaxController {

	private List<Person> listPerson = new ArrayList<Person>();

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView home() {
		ModelAndView mv = new ModelAndView("web.home");
		return mv;
	}

	@RequestMapping(value = "/addnew", method = RequestMethod.GET)
	public @ResponseBody String addNew(HttpServletRequest request) {
		String name = request.getParameter("name");
		String age = request.getParameter("age");

		Person person = new Person(name, Integer.parseInt(age));
		listPerson.add(person);

		ObjectMapper mapper = new ObjectMapper();
		String ajaxResponse = "";
		try {
			ajaxResponse = mapper.writeValueAsString(person);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}

		return ajaxResponse;
	}

	@RequestMapping(value = "/search", method = RequestMethod.GET)
	public @ResponseBody String searchPerson(HttpServletRequest request) {
		String query = request.getParameter("name");
		Person person = searchPersonByName(query);

		ObjectMapper mapper = new ObjectMapper();
		String ajaxResponse = "";
		try {
			ajaxResponse = mapper.writeValueAsString(person);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}

		return ajaxResponse;
	}

	public Person searchPersonByName(String query) {
		for (Person p : listPerson) {
			if (p.getName().equals(query)) {
				return p;
			}
		}
		return null;
	}

**3)Model Class ** Person class có nhiệm vụ đóng gói dữ liệu của người dùng nhập vào hoặc dữ liệu được trả về của server !

public class Person {

	private String name;
	private int age;

	public Person() {

	}

	public Person(String name, int age) {
		this.name=name;
		this.age=age;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

**4)Jquery Ajax ** Trong file JSP, ta tạo 2 form thêm và tìm kiếm đơn giản gửi ajax request bằng $.ajax

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<c:url var="home" value="/" scope="request" />

<title>Spring Ajax Example</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
	integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7"
	crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css"
	integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r"
	crossorigin="anonymous">

</head>
<style type="text/css">
input[type="text"], input[type="number"] {
	display: block;
	width: 100%;
	height: 40px;
	margin-bottom: 10px;
}

.content {
	margin-top: 50px;
}

.navbar {
	color: white;
	background-color: #45619D !important;
	border-radius: 0px;
}

.navbar-header {
	border-radius: none;
}

.navbar-header a {
	margin-top: 10px;
	font-size: 30px;
}

.navbar-header a:hover {
	color: white;
}

.btn {
	width: 100%;
}

#ajax-response {
	text-align: center;
	margin-left: 20px;
	border: 1px solid black;
	margin-bottom: 10px;
	padding-bottom: 20px;
}
</style>
<body>

	<header> <nav class="navbar">
	<div class="container">
		<div class="row">
			<div class="col-md-6">
				<div class="navbar-header">
					<a href="#" class="navbar navbar-brand">Viblo</a>
				</div>
			</div>
		</div>
	</div>
	</nav> </header>

	<section class="content">
	<div class="container">
		<div class="row">
			<div id="ajax-response"></div>
		</div>
		<div class="row">
			<div class="col-md-4">
				<h3>Add New Person</h3>
				<input type="text" placeholder="Enter name of person" name="name"
					id="name" /> <input type="number"
					placeholder="Enter age of person" name="age" id="age"> <input
					type="submit" class="btn btn-success" value="Submit"
					onclick="addViaAjax()">
			</div>
			<div class="col-md-4">
				<h3>Search Person by name</h3>
				<input type="text" placeholder="Enter name of person" id="query" />
				<input type="button" class="btn btn-success" value="Submit"
					onclick="searchViaAjax()">
			</div>
		</div>
	</div>
	</section>
	<script
		src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
	<script
		src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
		integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
		crossorigin="anonymous"></script>

	<script type="text/javascript">
		function addViaAjax() {

			var name = $("#name").val();
			var age = $("#age").val();

			$.ajax({
				type : "GET",
				contentType : "application/json",
				url : "${home}home/addnew/",
				data : {
					name : name,
					age : age
				},
				dataType : 'json',
				timeout : 100000,
				success : function(data) {
					console.log("SUCCESS: ", data);
					var result = "<h3> You just add new Person </h3>"
							+ "<strong>Name:</strong> " + data.name + "<br>"
							+ "<strong>Age:</strong> " + data.age;
					$("#ajax-response").html(result);
				},
				error : function(e) {
					console.log("ERROR: ", e);
				}
			});
		}

		function searchViaAjax() {

			var name = $("#query").val();

			$.ajax({
				type : "GET",
				contentType : "application/json",
				url : "${home}home/search/",
				data : {
					name : name
				},
				dataType : 'json',
				timeout : 100000,
				success : function(data) {
					console.log("SUCCESS: ", data);
					if (data != null) {
						var result = "<h3> You just search Person: "
								+ data.name + "</h3>";
						$("#ajax-response").html(result);
					} else {
						var result = "<h3 style='color:red'> No person found </h3>";
						$("#ajax-response").html(result);
					}
				},
				error : function(e) {
					console.log("ERROR: ", e);
				}
			});
		}
	</script>
</body>
</html>

5)Demo Bật terminal hoặc lên, đưa con trỏ vào vị trí của project và gõ lệnh
mvn jetty:run

Screen Shot 2016-04-18 at 9.40.25 PM.png

**5.1) Nhập tên và tuổi **

Screen Shot 2016-04-18 at 9.41.27 PM.png

**5.2) Kết quả ajax trả về từ server **
Ta đã sử dụng HTTP method GET nhưng dữ liệu vẫn k bị hiển thị lên url => việc nói POST bảo mật hơn GET vì dữ liệu không được đưa lên url là chưa đúng !

Screen Shot 2016-04-18 at 9.44.03 PM.png

Screen Shot 2016-04-18 at 9.46.22 PM.png

Screen Shot 2016-04-18 at 9.48.16 PM.png

Link download source code

https://www.dropbox.com/s/ov7wzcs49m3zgyx/viblo-spring-learn-ajax.zip?dl=0