本章构建并部署一个 MVC web app.
a web application my constant
- static content
- JSP pages
- servlet classes
- the deployment descriptor (DD)
- tag libraries
- JAR files
- Java class files
DD 元素的目标和语义
- error-page
- init-param
- mime-mapping
- servlet
- servlet-class
- servlet-mapping
- servlet-name
- welcome-file
体会一整套的构建过程
- development environment
- deployment environment
- iterative development an testing
POJO (Plain Old Java Object)
部署目录不仅要符合 Servlets and JSP specifications
,还要慢速 Container-specific rules
,且不同的容易规定的部署目录有不同,比如 Tomcat
要求部署到 webapps
目录下。
构建一个 app 的路线图:
- reviewed the user views
- looked at the architecture
- setup the development and deployment environments for creating and deploying the app
- creating the app
- Build and test the HTML
- Build and test version 1 (invoked via the HTML form and prints the parameter it receives) of the controller servlet
- Build a test class
- Upgrade the servlet to version 2 (adds the capability of calling the model class to get beer advice)
- Build the JSP, upgrade the servlet to version 3 (which adds the capability of dispatching to the JSP)
书中引入了极限编程(extreme programming)、迭代开发(iterative development)的方法学,and mangle them for out own evil purposes… ; )
开发目录
beerV1
├─classes
│ └─com
│ └─example
│ ├─model
│ └─web
├─etc
│ web.xml
│
├─lib
├─src
│ └─com
│ └─example
│ ├─model
│ │ BeerExpert.java
│ │
│ └─web
│ BeerSelect.java
│
└─web
form.html
result.jsp
部署目录 (已在 webapps
下)
Beer-v1
│ form.html
│ result.jsp
│
└─WEB-INF
│ web.xml
│
├─classes
│ └─com
│ └─example
│ ├─model
│ └─web
└─lib
DD web.xml
模板
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
</web-app>
URL
+ <form>
标签的 action
属性 = request URL
eg. /Beer-v1 + /SelectBeer.do = /Beer-v1/SlectBeer.do
".do"不是真的文件后缀,而是一个逻辑名称。
命令行编译遇到的问题:
- Path and Class Path
- setting the Class Path
- 带多个path编译
- 找不到或无法加载主类
- including-jars-in-classpath-on-commandline-javac-or-apt
注:-cp = -classpath
因为 Java 安装在 Program Files 文件夹,空格导致断开,命令行无法识别。
D:\Development\eclipse-workplace\HW>javac -cp %CLASSPATH%;. -d classes src\com\example\web\BeerSelect.javajavac: 无效的标记: Files\Java\jdk1.8.0_192\lib\tools.jar;;.
用法: javac
-help 用于列出可能的选项
处理办法,重命名环境变量,短名称
处理办法2,用%引用
处理办法3,创建软连接
%~d0
how-are-the-digits-after-assigned-in-windows-short-file-names)
how-does-progra1-path-notation-work
wikipedia 8.3_filename
how-to-disable-8-3-file-name-creation-on-ntfs-partitions
最后的解决办法:放到没有空格的路径下。不要自找麻烦。
HttpServlet,setContentType 不要打错成 HttpServer, SelectContentType
package com.example.web;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class BeerSelect extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Beer Selection Advice<br>");
String c = request.getParameter("color");
out.println("<br>Got beer color " + c);
}
}
# windows
.;D:\Program Files\Java\jdk1.8.0_192\lib\*.jar
# unix
.;D:/Program Files/Java/jdk1.8.0_192/lib/*.jar
# -cp 指定 classpath,这里需要tomcat含有的servlet-api,需要本项目下的classes(?这里仍然有疑问),需要当前目录., -d 指定编译后的 .class 存放的目录
$javac -cp D:\Development\tomcat\apache-tomcat-8.5.37\lib\servlet-api.jar;classes;. -dclasses src\com\example\web\BeerSelect.java
Model 应该独立。
package com.example.model;
import java.util.*;
public class BeerExpert {
public List getBrands(String color){
List brands = new ArrayList();
if(color.equals("amber")){
brands.add("Jack Amber");// 警告: [unchecked] 对作为原始类型List的成员的add(E)的调用未经过检查
brands.add("Red Moose");// 警告: [unchecked] 对作为原始类型List的成员的add(E)的调用未经过检查
}else{
brands.add("Jail Pale Ale");// 警告: [unchecked] 对作为原始类型List的成员的add(E)的调用未经过检查
brands.add("Gout Stout");// 警告: [unchecked] 对作为原始类型List的成员的add(E)的调用未经过检查
}
return (brands);
}
}
//注: src\com\example\model\BeerExpert.java使用了未经检查或不安全的操作。
//注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
编译警告的解决办法:类前面加注解:@SuppressWarnings(“unchecked”)
修改 servlet 类
package com.example.web;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*; // List, Iterator
import com.example.model.*;
public class BeerSelect extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Beer Selection Advice<br>");
String c = request.getParameter("color");
// out.println("<br>Got beer color " + new BeerExpert().getBrands(c));
BeerExpert be = new BeerExpert();
List result = be.getBrands(c);
Iterator it = result.iterator();
while (it.hasNext()) {
out.print("<br>try: " + it.next());
}
}
}
调试的时候要注意清空 Firefox 的缓存,否则 form.html
的改动不会被加载进来。
修改 call JSP
BeerSelect.java
package com.example.web;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*; // List, Iterator
import com.example.model.*;
public class BeerSelect extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// response.setContentType("text/html");
// PrintWriter out = response.getWriter();
// out.println("Beer Selection Advice<br>");
String c = request.getParameter("color");
BeerExpert be = new BeerExpert();
List result = be.getBrands(c);
request.setAttribute("styles",result);
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
view.forward(request, response);
}
}
result.jsp
<%@ page import="java.util.*" %>
<html>
<body>
<h1 align="center">Beer Recommendations JSP</h1>
<P>
<%
List styles = (List)request.getAttribute("styles");
Iterator it = styles.iterator();
while(it.hasNext()){
out.print("<br>try: "+it.next());
}
%>
</P>
</body>
</html>
至此,相当于第一次打通 B/S 端。
source code