在编写JavaWeb项目前需要掌握的要点
1、环境的搭建
1.1、tomcat的安装
点击进入tomcat官网,在网页的左边框有个Download选项,选择tomcat的版本下载,我推荐的话8版本和9版本,如图所示:
右下角的是选择对应的操作系统的位数,
如果官网进不去,就保存我发的压缩包(百度云盘),
链接:https://pan.baidu.com/s/1jfnNfWv3ABes0JMFBIGZnw
提取码:hco6
我给了两个版本的tomcat,8版本的是免安装的直接放在你想要放的位置就行,而9版本的是安装版本,需要进行安装操作,安装也是很简单的点击下一步的操作。
注意:选择安装的路径时不要选择文件名存在中文和空格,不然接下来的配置环境变量时会出问题。
1.3、tomcat的配置
首先需要打开高级系统设置(点击我的电脑,打卡页面后,右键空白区域选择属性这一选项,点击进入即可看到高级系统设置的选项了),接着点击环境变量按钮进入环境配置需要配置的系统变量有两个,一个是增加一个变量名为: CATALINA_HOME、变量值为:你安装tomcat的路径,如图所示:
每个人的安装路径可能不同,一定要选择自己的安装路径,不然是无效的。第二个需要增加的Path变量的变量值,这个变量名在系统变量中是默认存在的,找到它,并点击编辑,在该变量下,需要增添两个变量值:%CATALINA_HOME%\bin 和 %CATALINA_HOME%\lib,如图所展示:
注意:在配置tomcat之前先得安装和配置好JDK,不然也是无效的,JDK的安装在我的这篇博文“Java基础介绍”中有介绍,没安装的小伙伴可以自行了解。
1.3、确认配置成功
配置好环境变量以后,打开安装tomcat的文件夹,找到该文件下的 bin 文件夹,然后找到 startup.bat 该文件,双击打开以后等待后会显示以下图例:
执行完后表示tomcat启动成功了,然后打开你的浏览器,在地址栏输入:http://localhost:8080后,出现以下图例则表示安装成功了。
如果遇到了无法解决的问题,则可以去访问这位大佬总结的解决方案
1.4、IDAE配置tomcat
安装和配置完tomcat之后,下面就在IDEA中配置装好的tomcat。
首先点击Run---EDit Configurations...
接着点击左侧“+”号,找到Tomcat Server---Local(若是没有找到Tomcat Server 可以点击最后一行 34 items more
之后在Tomcat Server ->local -> Server ->Application server项目下,点击Configuration,找到本地的tomcat服务器(就是你安装tomcat的地方),再点击OK按钮。至此,IDEA配置Tomcat就完成了
1.5、创建JavaWeb项目
以上操作都配置好以后就可以创建一个JavaWeb项目了,接下来介绍如何创建JavaWeb项目。
首先点击左上角的File -> New ->Project
接着选择Java Enterprise,在Application Server中找到自己的Tomcat,同时勾选Web Application
之后点击next进入下个界面,界面中第一个要填写的是你的工程名,第二个填的是工程要放在哪的路径,选择好以后点击finish,就创建了一个最基本JavaWeb项目了。
最后点击右上角的绿色小三角就可以启动JavaWeb项目了。
1.6、Tomcat的基本操作
可能有的小伙伴在运行时会显示端口号8080被占用了,那么可以更改Tomcat的端口号,那么如何修改端口号,接下来就来介绍一下吧。
首先找到安装Tomcat的文件夹,打开并找到conf文件夹,接着找到server.xml文件,之后用笔记本打开该文件,找到下图显示的代码处:
这个是更改端口号为8888之后的效果,没有更改之前 port=“8080”是默认的,还有一个特殊的端口号:80,如果把端口号改成80的话,在你输入地址访问项目时,可以不用输入端口号就可以访问。
2、认识并掌握Servlet
上面介绍了如何进行JavaWeb项目的环境搭建,接下来要介绍的内容都是重点,都必须熟练掌握,才可以了解JavaWeb项目的实现原理和过程,话不多说,直接进入Servlet的介绍
2.1、Servlet介绍
Servlet全称为:Java Servlet,它是由Java语言编写的服务器端的程序,主要的功能在于实现前后端的交互功能,通俗的说就是进行数据的浏览和修改,从而达到动态显示Web内容的效果。
因为它是由Java语言编写的,所以运行于支持Java的服务器中,而且多数情况下只用来扩展基于HTTP协议的Web服务器。
从servlet的工作模式可以看出,Servlet相当于前后端进行数据交互的通道,或者说是充当了转告者的身份。这是因为,在客户端发送请求时,服务器会先调用Servlet进行数据的处理,之后传给服务器处理后的内容,左后服务器再响应给客户端,说它是转告者是不是很生动。
2.2、Servlet的生命周期
在项目中,每一个Servlet都有自己的生命周期,生命周期可以反应某个Servlet的运行过程,让我们更好的管理Servlet。
Servlet的生命周期分为四个阶段:实例化阶段 -> 初始化阶段(该阶段调用 init() 方法) -> 处理请求阶段(该阶段调用 service()方法) ->服务终止阶段(该阶段调用 destory() 方法)
介绍完Servler的理论知识,下面介绍如何编写Servlet
2.3、Servlet的实现方式
在编写自定义的Servlet类时有两种比较常用的实现方式:实现Servlet接口和继承HttpServlet抽象类,不管是实现这两种方式的哪一种,自定义的类都可以重写以下三种基本的方法:
- init()方法——该方法在Servlet初始化时调用
- service()方法——该方法在处理客户端请求时调用,无论是get请求还是post请求都执行
- destroy()方法——该方法在Servlet服务结束时调用
当然也有不一样的:继承HttpServlet抽象类的方式,还可以选择重写这两个方法:
- doGet()方法——该方法在客户端进行get请求时调用
- doPost()方法——该方法在客户端进行post请求时调用
2.4、使用XML文件配置Servlet
当然你只是编写了Servlet的类是完全不够的,想要实现前后端的交互还得对Servlet类进行相应映射关系的配置,而配置映射关系需要按照以下步骤进行:
首先,找到项目文件夹:Web文件夹下的WEB-INF文件夹下的web.xml文件,然后双击打开,在这对标签之间添加一些配置代码,配置代码格式如下:
最后进行完善后的具体示例如下:
<servlet>
<!-- 这是自定义的名称,最好是你的类名,好分辨-->
<servlet-name>DispatcherServlet</servlet-name>
<!-- 这是你自定义类的完整路径(包名加类名)-->
<servlet-class>com.kaikeba.mvc.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 这是映射的名称,该名称要与上面的名称一致,不然会报错-->
<servlet-name>DispatcherServlet</servlet-name>
<!--这是请求名,这就是所有的以(.do)结尾的请求都会来到这个Servlet配置文件中-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
如此配置完以后,执行的过程是这样的:
首先,当客户端发起了请求时,就会先将上述的配置文件中 url-pattern 这个标签内的请求名与客户端的请求名相对比,如果客户端发起的请求名中不以.do结尾,就不执行接下来的步骤,如果客户端发起的请求名中以.do结尾,那么接下来将会拿 servlet-mapping 标签下的 servlet-name 标签中的值与 servlet 标签下的 servlet -name 标签中的值相匹配,不同则不执行接下来的步骤,相同则去找 servlet 标签下的 servlet-class 标签的完整路径,最后找到相应的自定义Servlet类。这就是从请求到找对应的不同的Servlet类的过程。
注意Servlet类可以有多个,只需要在web.xml中进行对应Servlet类的映射关系的配置即可,这样就可以使用不同的Servlet类来处理不同类型的请求。
2.5、request对象的使用
在使用继承HttpServlet类的方式所自定义的Servlet类中,由于HttpServlet该类中封装了HttpServletRequest的request对象,所以在自定义的Servlet类中,我们可以直接使用request对象,当然你会问,如果是使用实现Servlet的方式自定义Servlet类,有没有request对象呢,答案是当然有,不过与HttpServlet中的request有一些不同,因为HttpServlet类是对Servlet接口的扩展,所以HttpServletRequest是扩展于ServletRequest。request对象的作用是:协助Servlet进行请求操作
介绍了request由来和作用,下面来介绍该对象可以实现的方法,可以实现的方法有以下几个:
- String getParameter(String name)——根据表单组件的名称或键值对中的键,来获取提交的数据(如:输入框、单选框、超链接等等)
- String[ ] getParameterValues(String name)——根据表单组件的名称获取多个提交的数据(如:多选框)
- void setCharacterEncoding(String charset)——指定每个请求的编码(针对post请求起作用)(字符集编码:utf-8、GBK等等)
- RequestDispatcher getRequestDispatcher(String path)——跳转页面(该方法称为转发),该方法返回的ReuqestDispatcher对象需要使用forward()方法进行转发要求,例如:
request.getRequestDispatcher("/index.html").forward(request,response);
- request.setAttribute(“key”,“value”);——该方法可以实现存值操作,该操作的意义在于在进行页面跳转时进行传值操作(注意:方法中传入的两个值代表的意义是:key代表存的值的标识,value代表你要存的值)
- request.getAttribute(“key”)——该方法可以实现取值的操作,依靠值的标识key进行值的获取。
- request.getSession()——获取HttpSession对象
2.6、Respone对象的使用
在使用继承HttpServlet类的方式所自定义的Servlet类中,由于HttpServlet该类中封装了HttpServletResponset的response对象,所以在自定义的Servlet类中,我们可以直接使用response对象,和request对象一样,HttpServletResponse也是扩展于ServletResponse。response对象的作用是:协助Servlet进行响应操作
接下来介绍response对象可以实现的几个方法
- void addCookie(Cookie var)——给响应添加一个Cookie
- void senRedirect(String path)——是浏览器跳转到某一地址(该方法称为重定向)
- PrintWriter getWriter()——获得字符流,可以将字符串通过字符流存到response缓冲区中
- setContentType()设置响应内容的类型
可以看到使用两个对象都可以进行页面的跳转的操作,但两种方法是有本质的区别的。Request对象使用的是转发操作,该操作属于一次请求一次响应,而Response对象使用的重定向操作,该操作属于两次请求两次响应。如图所示:
2.7、Request、Session和Cookie
上述介绍中提到了request、session和cookie这三个在进行会话操作时会使用的三个进行存值的对象,虽然都是进行存值操作,但是,三者是有区别的。
Request对象存的值只能在单次请求中存在,即保存的值不能跨页面存在。因此,Request对象存的值在进行重定向时会丢失数据,但进行转发操作则不会出现丢失数据的现象。
Session对象存的值可以在多个页面中共享,也就是说在进行转发和重定向操作都不会发生数据丢失现象,这就是Session对象和Repuest对象的不同之处,而且该对象存的值是保存在服务器内存中的。
Cookie对象存的值也是可以在对个页面下共享,但和Session不一样的是,Cookie对象存的值是保存到客户端的内存中的。
2.8、请求方式的分类
客户端给服务器发送请求的方式分为两种:get请求和post请求。使用get请求发送的数据拼接到地址的后面,以?号分割地址与数据,以&符号分割多个数据。而使用post请求会把数据放在Http请求包中,因此不会显示到地址栏中。
由上面介绍的两种请求的特性决定了在进行特定的数据交互时只能选择post请求,比如进行注册和登录操作时,使用get请求是不太合理的,因为用户的密码会拼接到地址栏中,安全性低。此外,由于限制于地址的长度限制,在进行大容量的数据交互时,必须使用post请求。(比如:图片、音频等等)。
介绍完get请求和post请求后,现在来总结以下客户端给服务器发送数据的方式,以及这些方式中那些是get请求,哪些是post请求。
- 通过表单的get或post提交——这种方式可以试试get请求也可以是post请求,由表单的method属性决定
<form action="/login" method="post" name="form">
<input type="text" name="name" />
<input type="password" name="passWord" />
<input type="submit" value="提交" />
</form>
- 使用a标签发送数据——属于get请求
<a href="/login?a=10&name=abc&pass=123">
- 使用地址栏拼接数据——属于get请求
- js提交数据——属于get请求
function login(){
location.href='/login?name=abc&pass=123';
}
2.9、注解的方式配置Servlet
在Servlet3.0之后,提供了使用注解的方式处理Servlet的映射关系,使用这种方式操作简单,而且不需要在web.xml中加任何代码,保持了web.xml文件的代码简洁。
注解的格式:使用@WebServlet该注解进行Servlet的配置,在该注解中含有几个属性,这些属性决定了你的Servlet的映射关系
@WebServlet(name = "myUserServlet",
urlPatterns = "/user/test", //斜杠必须
loadOnStartup = 1,
initParams = {
@WebInitParam(name="name", value="小明"),
@WebInitParam(name="pwd", value="123456")
}
)
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 7109220574468622594L;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("servlet初始化...");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter pw = response.getWriter();
pw.append("Hello Servlet!<br>" );
//servletName
pw.append("servletName:" + getServletName() + "<br>");
//initParam
ServletConfig servletConfig = this.getServletConfig();
Enumeration<String> paramNames = servletConfig.getInitParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
pw.append(paramName + ":" + servletConfig.getInitParameter(paramName) + "<br>");
}
pw.close();
}
}
地址栏中输入:http://localhost:8080/user/test
在网页中输入的效果为以下图示:
.urlPatterns的常用规则:
- */或者/:所有地址都会进入该Servlet
- *.do:指定地址后缀进入该Servlet
- /user/test:指定该地址才可以进入Servlet
- /user/.do、/.do、test/*.do都是非法的,启动时候会报错
3、认识并掌握JSP
上面介绍了Servlet在后端的应用,但Servlet的应用不仅仅是在后端,它在前端的应用也不少。Servlet在前端的应用涉及到了一种新的前端页面:JSP,接下来就来介绍JSP的相关内容。
3.1、JSP的介绍
JSP全称为:Java Server Pages,它是由多家公司一起参与建立的一种动态网页技术的标准,JSP技术根本就是一个简化的Servlet设计技术,它是在传统的HTML网页中插入Java程序段和JSP标记,从而形成JSP文件,后缀名为(*.jsp)。
3.2、JSP的特点
使用JSP开发的特点有以下几点:
- 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其它操作系统上运行。
- 使用JSP技术设计的网页,该页面的数据是动态更新的
- 使用JSP技术设计页面可以嵌入Java代码
- JSP技术本质上也是一个Servlet
3.3、Java代码如何嵌套进JSP页面中
既然了解到了JSP技术可以在HTML网页中嵌入Java代码,那么知道JSP页面是如何嵌套Java代码的是学习好JSP技术的基础,接下来就来介绍JSP嵌套Java代码小脚本的语法。
先说明为什么JSP页面可以嵌套JSP代码,这是因为在JSP页面中有这一段指令:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
如果你发现你的JSP不能执行嵌套的Java代码时,检查一下这段指令是否被你误删了,没有就加上这段指令,这段指令是默认生成的,无需手动添加。
嵌套Java代码需要了解的几个标签:
- <%! %>——变量和方法的声明标签
<%! int a = 10;%> <!--声明成员变量a-->
<%! public void show(){}%> <!--声明成员方法show() -->
- <%= %>——取值显示在页面的声明标签
<%=a%> <!--输出变量a的值-->
- <% %>——编写Java代码段的声明标签,该标签之中可以编写一段Java代码段
<%
int i = 0;
out.println("i的值为:"+i);
%>
- <%@ page imput=“包名” %>
<%@ page imput="java.util.*" %>
上述的就是JSP嵌套Java代码的 几个标签了。
3.4、JSP的九个内置对象
JSP中封装了9个内置对象,这些对象不需要我们自己定义,直接拿来用即可。这九个内置对象分别是:
- request——该对象是HttpServletRequest类型的对象,和上面介绍HttpServlet的Request对象是一样的语法和作用。
- response——该对象是HttpServletResponse类型的对象,该对象的作用域只在JSP页面,作用是将JSP容器处理的对象传回给客户端。
- session——该对象是HttpSession类型的对象,该对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存用户信息,跟踪用户操作状态,该对象保存的信息只在用户访问浏览器时有效,退出浏览器就失效了。
- application——该对象也可以将信息保存在服务器中,该对象保存的信息在服务器关闭时才会失效,因此与session对象比application对象的生命周期更长。
- pageContext——该对象的作用是:获取任何范围的参数,通过它可以获取JSP页面的request、out、response、session、application等对象。
- config——该对象的作用主要是获取服务器的配置信息。
- page——该对象代表JSP本身,因此只有在JSP页面中才是合法的。
- out——该对象的作用用于在Web浏览器中输出信息,在使用该对象进行输出数据时,会及时处理缓冲区中的残余数据。
- exception——该对象的作用是显示异常信息,在JSP页面中出现没有捕获的异常,就会生成该对象,然后把该对象传送到Page指令中设定的错误页面中,然后在错误页面中处理该对象。
<!--在page指令中(errorPage="error.jsp")该属性就是设置的错误页面-->
<%@ page errorPage="error.jsp" contentType="text/html;charset=UTF-8" language="java" %>
<!--注意:在错误页面(error.jsp)中的page指令中需要添加(isErrorPage="true")的属性 -->
<%@ page language="java" isErrorPage="true" contentType="text/html;charset=UTF-8" %>
3.5、JSP的三大指令
在JSP页面中JSP指令用来设置整个JSP页面相关的属性,如网页的编码方式和脚本语言。
JSP中有三大指令,如图所示:
一个JSP页面可以包含多个Page指令,Page指令的语法格式:<%@ page 属性=“值”%>,page指令的属性列表如下:
Include指令的作用是:JSP页面可以使用include指令来包含其他文件,被包含的文件可以是JSP文件、HTNL文件或其他文本文件。Include指令的语法格式为:<%@ include file="文件的相对路径"%>,如果你没有给文件关联一个路径、那么JSP编译器默认在当前路径下寻找。
Taglib指令的作用是:允许用户引入一个自定义标签集合,该指令的语法格式为:<%@ taglib uri="标签库的位置" prefix=“自定义的标签库名称”%>
3.6、EL表达式
在JSP中使用EL表达式,可以简化对象和变量的取值时的代码操作,在引入EL表达式之前,使用<%= %>来进行取值,使用EL表达式将会大大简化取值的代码编写。
使用EL表达式进行取值的语法格式:${需要显示的信息},注意:EL表达式进行的取值操作是从pageContext—>request—>session—>application这些对象存储的值中查找,如果没有指定变量或对象的范围时,会依照上述的顺序进行一次寻找,因此需要把你要显示的值存入上述的几个对象中。
如何获取上述几个对象中存储的值,需要知道上述对象对相应的隐含对象,通过 隐含对象.键 来获取键值对中的值。每个对象对应的隐含对象如下:
- pageScope对象,用于获取当前页面的属性值——对应pageContext对象
- requestScope对象,用于获取请求范围的属性值——对应request对象
- sessionScope对象,用于获取会话范围的属性值——对应session对象
- applicationScope对象,用于获取程序范围的属性值——对应application对象
EL表达式中还可加入以下运算符或操作符,例如:
3.7、JSTL标签库
JSTL是一个JSP标签集合,它封装了JSP中通用的核心功能,比如:迭代、条件判断、国际化标签、SQL标签等等。
根据JSTL标签所提供的功能,可以将其分为5个类别:核心标签、格式化标签、SQL标签、xml标签、JSTL函数。
使用JSTL标签库时,需要引入standard.jar 和 jstl.jar这两个jar包。使用时需要借助taglib指令来引入,格式为<%@ taglib prefix="页面使用的名称(下图的前缀)" uri="功能的路径(下图的Uri)"%>
JSTL标签库的jar包百度云盘链接
链接:https://pan.baidu.com/s/1YD3MqT-QEjOk_PhX7d5hdA
提取码:x682
功能范围 | uri | 前缀 | 类别 |
---|---|---|---|
core | http://java.sun.com/jsp/jstl/core | c | 核心标签 |
fmt | http://java.sun.com/jsp/jstl/fmt | fmt | 格式化标签 |
sql | http://java.sun.com/jsp/jstl/sql | sql | SQL标签 |
xml | http://java.sun.com/jsp/jstl/xml | xml | xml标签 |
functions | http://java.sun.com/jsp/jstl/functions | fn | JSTL函数标签 |
<!--编写示例-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
常用的是c标签库,就介绍c标签库中的几个使用的标签:
- <c:if> </c:if> ——进行 if 判断,如果为true,这输出标签体中的内容,下面是该标签的属性:
名称 | 说明 | 是否必须写 | 默认值 |
---|---|---|---|
Test | 该属性的值为判断的表达式,为true时,则执行标签体中的内容 | 是 | 无 |
var | 用来存储结果(true或false) | 否 | 无 |
scope | var变量的JSP范围 | 否 | page |
<c:if test="4>5">
4>5 <!--该内容不输出-->
</c:if>
- <c:choose> </c:choose>、<c:when> </c:when>、<c:otherwise> </c:otherwise> ——相当于if-else,标签属性有:
名称 | 说明 | 是否必须写 | 默认值 |
---|---|---|---|
Test | 表达式为true时,则执行该内容 | 是 | 无 |
<c:choose>
<c:when test="4>5">
4>5 <!--该内容不输出-->
</c:when>
<c:otherwise>
4<5 <!--该内容输出-->
</c:otherwise>
</c:choose>
- <c:forEach> </c:forEach>——相当于循环,可以用来遍历数组、集合
名称 | 说明 | 是否必须写 | 默认值 |
---|---|---|---|
var | 用来存放指定的成员 | 是 | 无 |
items | 被迭代的集合或数组对象 | 否 | 无 |
<%
int[] a = {1,5,7,6,4};
request.setAttribute("array",a);
%>
<c:forEach items="${requestScope.array}" var="b">
${b}
<c:forEach>
以上就是关于JSP的相关内容了。
4、认识并掌握Filter
4.1、Filter的介绍
过滤器实际上是对web资源进行选择性的拦截,进行一些处理之后再交给下一个过滤器或是Servlet处理。
4.2、Filter的语法格式
首先创建一个类实现Filte接口,接下来重写接口中的方法:destroy()、doFilter()、init(),
public class CharSetFilter implements Filter{
public void destroy() { //销毁的方法}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
/*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/
}
}
然后需要在web.xml文件中配置以下映射关系(和Servle的映射配置相似)
<filter>
<filter-name>CharSetFilter</filter-name>
<filter-class>com.kaikeba.filter.CharSetFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharSetFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
当然也可以使用注解的方式进行映射配置
@WebServlet(name = "CharSetFilter",
urlPatterns = "/*")
public class CharSetFilter implements Filter{
public void destroy() { //销毁的方法}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
/*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/
}
}
4.3、Filter的应用
过滤器可以应用在以下几个场景:
- 页面访问的权限设置
- 设置统一的编码
- 密码的加密与解密
- 非法文字的筛选
- 下载资源的限制
5、认识JavaWeb MVC
5.1、JavaWeb MVC的介绍
JavaWeb MVC与标准的MVC概念一样,分为三大部分:Model(模型)、View(视图)、Controller(控制器),在Web MVC模式下,模型无法主动推数据给视图,如果用户想要视图更新,需要再发送一次请求(即请求-响应模型)。
Model (模型) : 应用程序的核心功能,管理这个模块中用的数据和值(bean包,dao包);
View(视图): 视图提供模型的展示,管理模型如何显示给用户,它是应用程序的外观;(jsp页面、html页面)
Controller(控制器): 对用户的输入做出反应,管理用户和视图的交互,是连接模型和视图的枢纽。(servlet包、service包)
5.2、自主编写框架模式下的Servlet
在编写大型项目中,如果还是使用一种请求对应一个Servlet的模式编写项目的话,那么就会需要编写大量的Servlet类,不利于项目的开发,那么如果将所有的Servle类的处理整合成一种框架模式,那么在实现请求的处理时将会大大减少编写重复代码的时间。下面就来演示如何编写一个依赖于Java中注解与反射机制的处理请求的框架模式。
首先需要在src文件夹下创建一个properties文件,该文件的是一个个键值对,其中值为处理请求的类(controller类)的完整路径,在该类中可以有多个方法进行不同的请求操作。
#配置文件中包含键值对,其中的值为处理请求的类,键随意但必须存在。
a=com.kaikeba.controller.Controller
之后在web.xml中配置Servlet的相关映射:
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.kaikeba.mvc.DispatcherServlet</servlet-class>
<!-- 配置加载时的配置文件-->
<init-param>
<!-- 描述配置文件的参数:contentConfigLocation-->
<param-name>contentConfigLocation</param-name>
<!-- 配置文件名:application.properties,文件创建在src文件夹下-->
<param-value>application.properties</param-value>
</init-param>
<!-- 项目加载时启动servlet-->
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!-- 跳转的网址 -->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
接着在src下创建一个文件夹mvc(自定义)文件夹下需要定义以下几个重要的类、注解和枚举:
- DispatcherServlet类——该类属于Servlet类
- HandlerMapping类——该类是对Controller类中的方法进行映射处理
- ResponseText注解——该注解是作用在Controller类中的方法上,表示该方法在某个请求下执行后响应回客户端的是文本信息。
- ResponseView注解——该注解的作用在Controller类中的方法上,表示该方法在某个请求下执行后响应回客户端的是页面跳转操作。
- ResponseType枚举——该枚举中定义了两个常量:Text和View,Text表示ResponseText、View表示ResponseView
- Contorller类——该类是进行请求处理的类
以下是Java代码:
- DispatcherServlet类的编写
package com.kaikeba.mvc;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @Author: Gyx
* @Date: 2021/2/22 16:52
*/
@WebServlet(initParams = {
@WebInitParam(name = "code",value = "utf-8")
})
public class DispatcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取用户输入的uri
String uri = req.getRequestURI();
//2.通过HandlerMapping类调用静态方法获取地址的映射对象
HandlerMapping.MvcMapping mapping = HandlerMapping.get(uri);
//2.1.判断地址映射是否存在
if(mapping==null){
resp.sendError(404,"该映射地址不存在"+uri);
}
//3.获取映射对象中的内容:类、方法、枚举类型
Object obj = mapping.getObj();
Method method = mapping.getMethod();
String result = null;
try {
result =(String) method.invoke(obj, req, resp);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
switch (mapping.getType()){
case TEXT:
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write(result);
break;
case VIEW:
resp.sendRedirect(result);
break;
}
}
@Override
public void init(ServletConfig config) throws ServletException {
//1.通过config调用getInitParameter()方法,获取配置文件名称,方法参数为描述配置文件的参数
String path = config.getInitParameter("contentConfigLocation");
//2.通过当前类加载配置文件,并获得输入流
InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
//3.通过HandlerMapping的静态方法load加载配置文件
HandlerMapping.load(is);
}
}
- HandlerMapping类的编写
package com.kaikeba.mvc;
/**
* @Author: Gyx
* @Date: 2021/2/22 17:39
*/
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 映射器(包含了大量的网址与方法)
*/
public class HandlerMapping {
private static Map<String,MvcMapping> data = new HashMap<>();
/**
* 获取映射对象
* @param uri 用户传入的网址
* @return 映射对象
*/
public static MvcMapping get(String uri){
return data.get(uri);
}
/**
* 加载配置文件中的内容:类、方法、注解等
* @param is 配置文件的输入流
*/
public static void load(InputStream is){
//1.加载配置文件
Properties ppt = new Properties();
try {
ppt.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//2.取出配置文件中键值对的值
Collection<Object> values = ppt.values();
//3.遍历每个值:oClass
for (Object o:values) {
//4.将值转化成字符串类型:className
String className = (String) o;
try {
//5.通过反射加载配置文件中的每个类
Class aClass = Class.forName(className);
//6.通过aClass调用getConstructor方法获得无参构造方法,
// 然后调用newInstance方法创建配置文件中值所对应的类的对象
Object object = aClass.getConstructor().newInstance();
//7.通过aClass调用getMethods方法获取类中的所有方法
Method[] methods = aClass.getMethods();
//8.遍历每一个方法
for (Method m:methods) {
//9.获取方法的所有注解
Annotation[] annotations = m.getAnnotations();
//10.判断是否有注解
if(annotations!=null){
//11.遍历所有的注解
for (Annotation a:annotations ) {
//12.判断注解的类型
if(a instanceof ResponseText){
//说明此方法返回文本
//13.创建MvcMapping对象,传入类对象,方法对象,枚举类型
MvcMapping mapping = new MvcMapping(object,m,ResponseType.TEXT);
//14.往集合中存入注解的值和MvcMapping对象
MvcMapping put = data.put(((ResponseText) a).value(), mapping);
//15.判断编写请求地址是否重复,不重复put对象为空
if(put!=null){
throw new RuntimeException("请求地址重复"+((ResponseText) a).value());
}
}else if(a instanceof ResponseView){
//说明此方法跳转页面
//13.创建MvcMapping对象,传入类对象,方法对象,枚举类型
MvcMapping mapping = new MvcMapping(object,m,ResponseType.VIEW);
//14.往集合中存入注解的值和MvcMapping对象
MvcMapping put = data.put(((ResponseView) a).value(), mapping);
//15.判断编写请求地址是否重复,不重复put对象为空
if(put!=null){
throw new RuntimeException("请求地址重复"+((ResponseView) a).value());
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 映射对象,每个对象封装了一个方法,用于处理请求
*/
public static class MvcMapping{
private Object obj;
private Method method;
private ResponseType type;
public MvcMapping() {
}
public MvcMapping(Object obj, Method method, ResponseType type) {
this.obj = obj;
this.method = method;
this.type = type;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public ResponseType getType() {
return type;
}
public void setType(ResponseType type) {
this.type = type;
}
}
}
- ResponseText注解的编写
package com.kaikeba.mvc;
import java.lang.annotation.*;
/**
* @Author: Gyx
* @Date: 2021/2/22 17:16
*/
@Target(ElementType.METHOD)//元注解:标注为使用在方法上
@Retention(RetentionPolicy.RUNTIME)//注解在执行时生效
@Documented//保存到文档
/**
* 注解的作用
* 被此注解标注的方法会用于处理请求
* 方法返回的内容是文字形式
*/
public @interface ResponseText {
String value();
}
- ResponseView注解的编写
package com.kaikeba.mvc;
import java.lang.annotation.*;
/**
* @Author: Gyx
* @Date: 2021/2/22 17:22
*/
@Target(ElementType.METHOD)//元注解:标注为使用在方法上
@Retention(RetentionPolicy.RUNTIME)//注解在执行时生效
@Documented//保存到文档
/**
* 注解的作用
* 被此注解标注的方法会用于处理请求
* 方法返回的内容是跳转的页面
*/
public @interface ResponseView {
String value();
}
- ResponseType枚举类的编写
package com.kaikeba.mvc;
/**
* @Author: Gyx
* @Date: 2021/2/22 17:31
*/
/**
* 枚举类型
*
*/
public enum ResponseType {
/**
* TEXT 表示文本
* VIEW 表示视图
*/
TEXT,VIEW;
}
- Controller类的编写(该类视具体的项目而变化、我这是最简单的示例)
package com.kaikeba.controller;
import com.kaikeba.mvc.ResponseText;
import com.kaikeba.mvc.ResponseView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: Gyx
* @Date: 2021/2/22 18:58
*/
public class Controller{
//该注解中的值为用户访问的地址
@ResponseText("/login.do")
public String login(HttpServletRequest request, HttpServletResponse response){
return "登陆成功";
}
//在执行该请求时先创建好success.jsp页面
@ResponseView("/logon.do")
public String logon(HttpServletRequest request,HttpServletResponse response){
return "success.jsp";
}
//该请求地址不进入Servlet
@ResponseView("/login1")
public String login1(HttpServletRequest request,HttpServletResponse response){
return "登陆成功";
}
//该请求返回的响应页面不存在
@ResponseView("/logon1.do")
public String logon1(HttpServletRequest request,HttpServletResponse response){
return "success.html";
}
}
具体的执行流程是:用户输入一个请求地址,之后进入web.xml文件进行匹配(*.do),以.do结尾的请求地址将会进入DispatcherServlet类,接着通过执行DispatcherServlet类的初始化方法:init()方法,执行HandlerMapping的静态方法:load()方法,在HandlerMapping类中的load()方法执行后,会获得Controller类中的所有方法的注解信息和执行结果,然后再进行DispatchterServlet类中的service()方法获取用户输入的请求地址,将用户输入的地址与Controller类中的所有方法的注解信息相比较,相同则通过HandlerMapping的静态方法:get()方法来获取到该方法的执行结果和该方法的注解类型,最后通过判断注解类型,对方法的结果进行对应的响应处理。
以上将是框架下的执行流程。
6、认识并掌握AJAX
6.1、AJAX的介绍
AJAX是Asynchronous JavaScript and XML的简称(异步的JavaScript和XML),AJAX并不是一门新的编程语言,而是一种使用现有标准的新方法,AJAX是与服务器进行交换数据并更新部分网页的技术,使用该技术在进行上述操作后不会重新加载页面。
6.2、AJAX的原理
Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器。像—些数据验证和数据处理等都交给Ajax引擎自己来做,,只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
6.3、AJAX所包含的技术
- 使用CSS和XHTML来表示
- 使用DOM模型来交互和动态显示
- 使用XMLHttpReques来和服务器进行异步通信
- 使用JavaScript来绑定和调用
其中AJAX的核心是XMLHttpRequest对象,该对象有以下几个属性:
- onreadystatechange 属性——该属性存有处理服务器响应的函数
- readyState 属性——该属性存有服务器响应的状态信息,该属性的值有以下几种:
- responseText 属性——该属性的作用:可以通过该属性来取得服务器返回的数据
- 其他属性如下:
XMLHttpRequest对象可以使用的方法有以下几个:
- open()方法——开启AJAX服务器的方法,第一个参数为请求的方式、第二个参数指定页面的地址,第三个参数是否是异步请求(true为异步请求)
var xmlHttp=new XMLHttpRequest();
xmlHttp.open("GET","index.html",true);
- send(content)方法——将请求的数据content送往服务器
- 其他方法如下:
6.4、基于JS实现AJAX
<script>
//第一步:创建XMLHttpRequest对象
var xmlHttp;
if (window.XMLHttpRequest) {
//非IE
xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
//IE
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP")
}
//第二步:设置和服务器端交互的相应参数,向路径http://localhost:8080/JsLearning3/getAjax准备发送数据
var url = "http://localhost:8080/JsLearning3/getAjax";
xmlHttp.open("POST", url, true);
//第三步:注册回调函数
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
var obj = document.getElementById(id);
obj.innerHTML = xmlHttp.responseText;
} else {
alert("AJAX服务器返回错误!");
}
}
}
//第四步:设置发送请求的内容和发送报送。然后发送请求
var uname= document.getElementsByName("userName")[0].value;
var upass= document.getElementsByName("userPass")[0].value ;
var params = "userName=" + uname+ "&userPass=" +upass+ "&time=" + Math.random();
// 增加time随机参数,防止读取缓存
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8");
// 向请求添加 HTTP 头,POST如果有数据一定加加!!!!
xmlHttp.send(params);
</script>
6.5、基于JQuery实现AJAX
<script>
$(function(){
$.ajax({
url:"请求地址",
Type:"请求方式(get、post、put、delete)默认是get",
data:{"请求数据的键":"请求数据的值","请求数据的键":"请求数据的值"},
dataType:"请求的数据类型(html、text、json、xml、script、jsonp)",
success:function(data,dataTextStatus,jqxhr){
//请求成功时执行
},
error:function(jqxhr,textStatus,error){
//请求失败时执行
}
});
});
//get请求 url:请求的路径、data:发送的数据、success:成功函数、dataYype:返回的数据
$.get(url,data,function(result){
//请求成功时执行
},dataType);
//post请求 url:请求的路径、data:发送的数据、success:成功函数、dataYype:返回的数据
$.post(url,data,function(){
//请求成功时执行
},dataType);
</script>
以上就是关于AJAX的相关知识,好了这篇博文所涉及的知识就已经介绍完毕,希望这篇文章可以帮到你们,谢谢大家的阅读了,如果觉得文章不错的话可以关注我,我会不定期等更新关于Java相关知识的博文。