Java Web系列:Java Web 项目基础
1.Java Web 模块结构
JSP文件和AXPX文件类似,路径和URL一一对应,都会被动态编译为单独class。Java Web和ASP.NET的核心是分别是Servlet和IHttpHandler接口,因此无论是基础的Page文件(JSP、ASPX)方式还是后来发展的MVC方式(Spring MVC、ASP.NET MVC)都是基于核心接口的基础上再次封装和扩展(DispatcherServlet、MvcHandler)。
除JSP文件外,其他全部文件部署在应用目录的WEB-INF子目录下,WEB-INF目录可以认为是ASP.NET中将web.config文件、bin目录和App_开头的运行时目录存放在了一个统一的根目录中。
Java Web的配置文件web.xml也存放在WEB-INF目录下,而ASP.NET的配置文件web.config一般直接存放在应用目录下(ASP.NET其他目录同样可以有web.config文件)。ASP.NET将所有的引用和代码生成的dll都部署在bin中,而Java Web的引用jar和生成的class分别存放在WEB-INF的子目录lib和classes中(参考1)。
综上,类似ASP.NET中的web.config、bin、App_Data等,Java Web中的WEB-INF、web.xml、lib和classes是我们必须了解和掌握的。
|--Assembly Root
|---WEB-INF/
|--web.xml
|--lib/
|--classes/
- WEB-INF目录:Java Web文件的根目录。
- web.xml文件:配置文件(asp.net web.config)。
- lib目录:存放类库文件(asp.net bin)。
- classes目录:存放class文件(asp.net bin)。
2.Java Web项目的基本结构[Eclipse Dynamic Web Project]
Eclipse Dynamic Web Project项目
(1)可以配置需要编译的源码目录和输出目录,默认编译src目录下的源文件到build\classes目录下。
(2)可以配置WEB-INF的根目录,默认为WebContent。
(3)可以选择是否生成默认web.xml文件。
我们创建一个命名为DynamicWP的默认生成web.xml的Dynamic Web Proejct项目。文件结构如下:
|--DynamicWP
|--.settings/
|--build/
|--classes/
|--src/
|--WebContent/
|--META-INF/
|--MANIFEST.MF
|--WEB-INF/
|--web.xml
|--lib/
在Eclipse的项目资源管理器中DyanmicWP项目的视图如下:
|--DynamicWP
|--Deployment Desciptor
|--JAX-WS Web Services
|--Java Resources
|--JavaScript Resources
|--build
|--WebContent
|--META-INF/
|--MANIFEST.MF
|--WEB-INF/
|--web.xml
|--lib/
- .settings为Eclipse项目文件夹,存放了Eslipse项目的各种配置。在Eclipse项目视图中不可见。
- src目录存放源码。在Eclipse的项目视图中对应为Java Resources/src。
- build存放编译后的文件。
- 可以在类似的\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\DynamicWP目录中查看运行时的文件结构。
3.Maven Web项目的基本结构
鉴于目前Java IDE众多并且都有一定的拥泵,Eclipse的Java Web项目不具有可移植性。Maven即解决了项目结构的规范问题又提供了强大引用处理等强大的功能,在项目布局等方面已经是目前事实上的标准。Maven项目的主要结构如下(参考2):
|--root
|--pom.xml
|--src/
|--main/
|--java/
|--resources/
|--webapp/
|--test/
|--java/
|--resources
|--target/
Eclipse中新建一个Maven web app项目。文件结构如下:
|--MavenWP
|--pom.xml
|--.project
|--.classpath
|--.settings/
|--src/
|--target/
|--classes/
|--m2e-wtp/
- pom.xml:maven项目配置文件。
- .project文件和.classpath文件以及.settings目录和target/m2e-wtp目录下的文件为Eclipse项目配置文件。
- src和target:maven标准项目目录。
Eclipse4.5.1中对应的项目资源管理视图
|--MavenWP
|--Deployment Desciptor/
|--Java Resources/
|--JavaScript Resources/
|--Deployed Resources/
|--src
|--target
|--pom.xml
- 默认创建的项目会添加一个index.jsp并报错:使用maven搜索并添加servlet依赖更新后就可以正常运行。
- Java构建路径问题警告:使用maven搜索并添加compiler插件并配置configuration节点更新就可以消除。
- 墙的问题配置maven镜像,我采用的是http://maven.oschina.net/content/groups/public/。
- 默认创建的maven webapp缺少的src/main/java、src/test/java和src/test/resources等目录需要自己手动添加。
- 修改.settings/org.eclipse.wst.common.project.facet.core.xml,更新<installed facet="jst.web" version="3.1"/>。
- web.xml根节点开始部分修改如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
Maven的配置文件pom.xml:
<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.</modelVersion>
<groupId>me.test</groupId>
<artifactId>MavenWP</artifactId>
<packaging>war</packaging>
<version>0.0.-SNAPSHOT</version>
<name>MavenWP Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.</version>
</dependency>
</dependencies>
<build>
<finalName>MavenWP</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.servlet基础
正如ASP.NET的核心是IHttpHandler一样,Java Web的核心是Servlet接口,位于javax.servlet命名空间中。Filter的概念可以参考ASP.NET的HttpModule,Servlet中的各种Listener可以参考ASP.NET HttpApplicaiton中类似的event。无论是Java还是.NET的Web技术,都是基于HTTP协议的具体实现。Java Web和ASP.NET中的一些核心项对应如下:
| Java 参考3 | .NET | 备注 | |
| Core | javax.servlet.Servlet | System.Web.IHttpHandler | |
| HTTP Request | javax.servlet.ServletRequest | System.Web.HttpRequest | |
| HTTP Response | javax.servlet.ServletResponse | System.web.HttpResponse | |
| Cookie | javax.servlet.http.Cookie | System.Web.HttpCookie | |
| Session | javax.servlet.http.HttpSession | System.Web.HttpSessionState | |
| Application | javax.servlet.ServletContext | System.Web.HttpApplication | |
| Begin Request | javax.servlet.Servlet.RequestDispatcher | System.Web.HttpApplication.BeginRequest | event |
| Begin\End Request | javax.servlet.Servlet.ServletRequestListener | System.Web.HttpApplication.BeginRequest\EndRequest | event |
| Filter | javax.servlet.Filter | System.Web.IHttpModule | |
| Application Event | javax.servlet.ServletContextListener | System.Web.HttpApplication.Application_Start\Application_End | method |
Servlet和ASP.NET的简化示意图:

用于简化web.xml配置的Servlet的注解(3.0开始支持,在ASP.NET中没有对应项):
(1)WebServlet:作用在javax.servlet.http.HttpServlet的实现类上。
(2)WebFilter:作用在javax.servlet.Filter的实现类上。
(3)WebListener:作用在Listener的实现类上(javax.servlet.ServletContextListener、javax.servlet.ServletContextAttributeListener、javax.servlet.ServletRequestListener、javax.servlet.ServletRequestAttributeListener、javax.servlet.http.HttpSessionListener、javax.servlet.http.HttpSessionAttributeListener)。
(4)WebInitParam:结合WebServlet和WebFilter注解用来配置属性。
(5)MultipartConfig:作用在javax.servlet.http.HttpServlet的实现类上。标注请求是mime/multipart类型。
用于Servlet容器初始化的ServletContainerInitializer(可实现无web.xml,3.0开始支持,可类比ASP.NET的Application_Start方法):
(1)Servlet容器启动时查找ServletContainerInitializer的实例。
(2)ServletContainerInitializer实例使用HandlesTypes标注一个或多个类型,Servlet容器将在启动时扫描classpath,获取这些类型的实例。
(3)Servlet容器在启动时调用ServletContainerInitializer实现类的onStartup方法,该方法可以获取HandlesTypes标注的所有类型对象。
5.自定义Session
Session在存储安全性要求较高的会话信息方面是必不可少的,Session当然绝对不是用来存储用户登录状态的,但类似验证码等敏感信息却必须存储在Session中。对于分布式Web应用自定义Session支持独立的状态服务器或集群是必须的。
ASP.NET通过SessionStateModule通过配置文件配置实际的Session提供程序,Session提供程序实现了SessionStateStoreProviderBase,因此在ASP.NET中实现自定义Session是通过继承SessionStateStoreProviderBase实现,配置Session是通过Web.config。ASP.NET自定义session的代码参考github上的开源项目SQLiteSessionStateStore。

同理,Java Servlet中使用自定义Session通过Filter可以实现。由于不同的servlet容器对Session的实现不同,所以通用性最好的方式是继承HttpServletRequestWrapper重写getSession方法返回自定义的Session对象。Filter采用了职责链模式(chain of responsibility),HttpServletRequestWrapper采用了装饰模式(Decorator),可以通过《Head First 设计模式》阅读模式的相关内容。
(1)首先自定义继承HttpSession的MySession(为了便于演示,仅包装了容器的session并转发调用)。
import java.util.Enumeration; import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession; public class MySession implements HttpSession { private HttpSession _containerSession; public MySession(HttpSession session) {
this._containerSession = session;
} @Override
public long getCreationTime() {
return this._containerSession.getCreationTime();
} @Override
public String getId() {
return this._containerSession.getId();
} @Override
public long getLastAccessedTime() {
return this._containerSession.getLastAccessedTime();
} @Override
public ServletContext getServletContext() {
return this._containerSession.getServletContext();
} @Override
public void setMaxInactiveInterval(int interval) {
this._containerSession.setMaxInactiveInterval(interval);
} @Override
public int getMaxInactiveInterval() {
return this._containerSession.getMaxInactiveInterval();
} @SuppressWarnings("deprecation")
@Override
public HttpSessionContext getSessionContext() {
return this._containerSession.getSessionContext();
} @Override
public Object getAttribute(String name) {
return this._containerSession.getAttribute(name);
} @SuppressWarnings("deprecation")
@Override
public Object getValue(String name) {
return this._containerSession.getValue(name);
} @Override
public Enumeration<String> getAttributeNames() {
return this._containerSession.getAttributeNames();
} @SuppressWarnings("deprecation")
@Override
public String[] getValueNames() {
return this._containerSession.getValueNames();
} @Override
public void setAttribute(String name, Object value) {
this._containerSession.setAttribute(name, value);
} @SuppressWarnings("deprecation")
@Override
public void putValue(String name, Object value) {
this._containerSession.putValue(name, value);
} @Override
public void removeAttribute(String name) {
this._containerSession.removeAttribute(name);
} @SuppressWarnings("deprecation")
@Override
public void removeValue(String name) {
this._containerSession.removeValue(name);
} @Override
public void invalidate() {
this._containerSession.invalidate();
} @Override
public boolean isNew() {
return this._containerSession.isNew();
} }
(2)自定义继承HttpServletRequestWrapper的MyRequest
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession; public class MyRequest extends HttpServletRequestWrapper { public MyRequest() {
super(null);
} public MyRequest(HttpServletRequest request) {
super(request);
// TODO 自动生成的构造函数存根
} @Override
public HttpSession getSession(boolean create) {
return new MySession(super.getSession(create));
} @Override
public HttpSession getSession() {
return new MySession(super.getSession());
}
}
(3)自定义Filter将Request包装为MyRequest
import java.io.IOException; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest; @WebFilter("/*")
public class MyFilter implements Filter { @Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO 自动生成的方法存根 } @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(new MyRequest((HttpServletRequest) request), response); } @Override
public void destroy() {
// TODO 自动生成的方法存根 } }
通过注解配置了Filter,也可以通过原始的web.xml方式配置。
6.参考
1.https://docs.oracle.com/javaee/7/tutorial/packaging003.htm
2.http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
3.https://docs.oracle.com/javaee/7/tutorial/webapp005.htm
小结:
你至少应该知道的:
(1)配置文件:ASP.NET的web.config和Java的web.xml
(2)Web核心:ASP.NET的IHttpHandler接口和Java的Servlet接口
(3)拦截器:ASP.NET的HttpModule和Java的Filter
(4)应用程序事件:ASP.NET的HttpApplication event和Java的各种Listener
(5)启动器:ASP.NET的Application_Start和Java的ServletContainerInitializer
(6)引用管理:ASP.NET的Nuget和Java的Maven
感想:
ASP.NET的核心对象不像Java Servlet一样,从一开始就基于接口,这是缺点。但Java Servlet的核心对象全靠容器实现,就连HttpSession同样如此,这也是缺点。比如自定义个Session十分麻烦,没有像ASP.NET一样简单配置即可。另外Servlet的一些抽象定义有点过头了,不够简洁。
Java Web系列:Java Web 项目基础的更多相关文章
- java集合系列——java集合概述(一)
在JDK中集合是很重要的,学习java那么一定要好好的去了解一下集合的源码以及一些集合实现的思想! 一:集合的UML类图(网上下载的图片) Java集合工具包位置是java.util.* 二:集合工具 ...
- Java Web系列:Spring Boot 基础
Spring Boot 项目(参考1) 提供了一个类似ASP.NET MVC的默认模板一样的标准样板,直接集成了一系列的组件并使用了默认的配置.使用Spring Boot 不会降低学习成本,甚至增加了 ...
- Java Web系列:Spring Boot 基础 (转)
Spring Boot 项目(参考1) 提供了一个类似ASP.NET MVC的默认模板一样的标准样板,直接集成了一系列的组件并使用了默认的配置.使用Spring Boot 不会降低学习成本,甚至增加了 ...
- Java Web系列:Spring MVC基础
1.Web MVC基础 MVC的本质是表现层模式,我们以视图模型为中心,将视图和控制器分离出来.就如同分层模式一样,我们以业务逻辑为中心,把表现层和数据访问层代码分离出来是一样的方法.框架只能在技术层 ...
- Java Web系列:Spring Boot 基础 Spring Security基本使用
@OneToOne or @ManyToOne Caused by: org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com ...
- Java Web系列:Spring Security 基础
Spring Security虽然比JAAS进步很大,但还是先天不足,达不到ASP.NET中的认证和授权的方便快捷.这里演示登录.注销.记住我的常规功能,认证上自定义提供程序避免对数据库的依赖,授权上 ...
- Java面试系列--java基础
Java基础总结 JAVA中的几种基本数据类型是什么,各自占用多少字节. 八大基本数据类型,byte:8位,short:16位,int:32位,long:64位,float:32位,double:64 ...
- Java入门系列(一)基础概览
序言 Java语言的特点不使用指针而使用引用.
- 补习系列(1)-springboot项目基础搭建课
目录 前言 一.基础结构 二.添加代码 三.应用配置 四.日志配置 五.打包部署 小结 前言 springboot 最近火的不行,目前几乎已经是 spring 家族最耀眼的项目了.抛开微服务.技术社区 ...
- (Java 多线程系列)Java 线程池(Executor)
线程池简介 线程池是指管理同一组同构工作线程的资源池,线程池是与工作队列(Work Queue)密切相关的,其中在工作队列中保存了所有等待执行的任务.工作线程(Worker Thread)的任务很简单 ...
随机推荐
- Java HashMap 遍历方式探讨
JDK8之前,可以使用keySet或者entrySet来遍历HashMap,JDK8中引入了map.foreach来进行遍历. keySet其实是遍历了2次,一次是转为Iterator对象,另一次是从 ...
- modelsim 仿真xilinx fir ip
到现在不管fir ip 用的对不对,但是在使用modelsim是可以仿真fir ip的. 具体步骤: 1.仿真库,添加到modelsim目录配置文件: 2.将这个文件中的: :List of dyna ...
- 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #6 使用localmodconfig缩短编译时间
HACK #6 使用localmodconfig缩短编译时间 本节介绍使用make localmodconfig生成精简的.config文件,缩短内核编译时间的方法.为了能够应对各种各样的环境,发布版 ...
- Django学习---Form组件认证
Form组件认证 能够帮助我们做用户认证. 以前写我们自己写用户认证的时候,我们自己写HTML的form表单,点击提交,数据就被发送到后台,后台进行验证.在验证过程中我们就需要自己去写正则表达式去匹配 ...
- centos7.3部署django用uwsgi和nginx[亲测可用]
现在nginx nginx version: nginx/1.10.2 uwsgi 2.0.17 django2.0.5 都已经完成完毕,那么开始 uwsgi 配置 uwsgi支持ini.xml等多种 ...
- hex文件和bin文件区别
HEX文件和BIN文件是我们经常碰到的2种文件格式.因为自己也是新手,所以一直对这两个文件懵懵懂懂,不甚了解,最近在做STM32单片机的IAP更新,其中要考虑HEX文件和BIN文件,所以需要学习下这两 ...
- WordPress部署
WordPress部署 WordPress是一个门户.博客网站的制作工具,php开发,自带后台,可以很简便的安装主题,还拥有一个庞大的主题网站生态. 软件下载:https://cn.wordpress ...
- .net core 下的一个docker hello world
接触 docker 有段时间了,发现docker这个东西,真是越用越爽. 那就从零开始跑一个 docker simple . 方法一: 步骤一: dotnet new mvc --name myweb ...
- MyBatis 动态SQL注意事项
- org.json库下的json的基本使用
public class Users { private String username; private String password; public String getUsername() { ...