前言:
这里主要是自己大二的学校课程下的上机任务!
2022年4月17日14:50:29
Tomcat 部署项目的方式
Tomcat 部署项目的方式有 4 种:
- 将 web 项目整个文件夹,放在
%TOMCAT_HOME%/webapps
目录中,文件夹名作为 ContextPath - 将 web 项目打包成 war,放在
%TOMCAT_HOME%/webapps
目录中,war 文件名作为 ContextPath - 在
%TOMCAT-HOME%/conf/server.xml
的 Host 标签中添加以下内容(ContextPath 是 path 属性值)
<Context docBase="项目路径" path="/xxx" />
- 在
%TOMCAT_HOME%/conf/Catalina/localhost
中新建一个 xml 文件,xml 文件名作为 ContextPath
<Context docBase="项目路径"/>
war包:
第1个war包:
(1)最基本的servlet类生成和访问方法弄清楚Servlet接口,HttpServlet类,核心是了解方法
回答:
1.直接继承HttpServlet类,编写用户需要的Serlvet【类,组件,控制器】
Servlet接口
GenericServlet抽象类
HttpServlet类
重写doGet方法:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 直接输出到浏览器的文本
response.getWriter().append("Served at: ").append(request.getContextPath());
response.getWriter().append("hello,小小");
}
doPost方法中直接调用doGet方法:(post和get方法区别不大!):
// 转交给doGet处理
doGet(request, response);
2.采用了注解的配置方式,最简单的注解,只给出url-pattern即可,建议统一用小写
3.所有的命名建议和要求:见名知义,英文
@WebServlet("/servletdemo01")
同时可以知道servlet运行时会有这些流程:
当我们浏览器请求该servlet的话
就会调用init()和service()方法
(2)最基本的JSP页面的生成和访问方法
<p>
比如本例子中是http://localhost:8080//j2020051035_01_servletDemo_war/就是index.jsp的访问请求url
http://localhost:8080//j2020051035_01_servletDemo_war/index.jsp也可以访问index.jsp
http://localhost:8080//j2020051035_01_servletDemo_war/readme.jsp访问readme.jsp的请求url
</p>
(3)请访问本例中的每一个servlet的url,并观察浏览器或是服务器控制台的输出信息
略!
(4)学习web.xml文件中的相关节点,自行小结给一个servlet在容器中如何命名,如何指定url
通过改变servlet-mapping的url-pattern标签来改变
<servlet>
<servlet-name>ServletDemo02</servlet-name>
<servlet-class>com.feng.ServletDemo02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo02</servlet-name>
<url-pattern>/servletDemo02</url-pattern>
<!--这里的url-pattern就可以改变url-->
</servlet-mapping>
<servlet>
<servlet-name>ServletDemo03</servlet-name>
<servlet-class>com.feng.ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo03</servlet-name>
<url-pattern>/servletDemo03</url-pattern>
</servlet-mapping>
第2个war包:
(1)注解配置
答案见下一题
(2)xml配置
(3)两者的优缺点
答案是可以的,应用场景目前我还没遇到,初学者没有必要这样去使用,推荐选择使用servlet新的注解方式,十分方便。
第3个war包:
回答相关问题:
<h1>
<ul>
<li>本例演示和思考回答 </li>
<li>读完程序中的文档,即注释,如果有相关问题,则直接回答问题。 </li>
<li>不同域的数据共享情况 </li>
<ul>
<li>session域 </li>
<li>application域 </li>
<li>【还有两个域以后会系统讲解:page,request】 </li>
</ul>
<li>注意,在验证访问时,要使用两个不同的浏览器 </li>
</ul>
</h1>
通过输入localhost:8080/03/privateShow/index.html
进入输入privacte数字界面:
因为没有实现上下文对象, 只能在同一次对话下进行数据保存累加,即只能在一个浏览器中进行累加
通过输入localhost:8080/03/publicShow/index.html
进入输入public数字界面:
@WebServlet("/publicSum")
public class PublicSum extends HttpServlet
{
//声明上下文对象
ServletContext sc;
public void init()
{
//实例化上下文对象
sc=this.getServletContext();
}
其他方法...
}
有实例化上下文对象, 只要服务启动,在不同的服务器之间, 数据互通
* (1) request:只限于一次请求
* (2) session:一次会话(多次请求)
* 开始
* 用户向服务器发送请求的时候
* 结束
* 客户端
* 丢失JsessionId值的时候(关闭浏览器)
* 服务器端
* 关闭服务器
* 超过会话的不活动周期时间
* (3) application:项目的加载到卸载
* (4) page域: 单当前页面
如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前jsp页面里。
从把变量放到pageContext开始,到jsp页面结束,你都可以使用这个变量。
三者参考链接戳这里
四者参考链接戳这里
第4个war包:
相关实验要求:
<pre>
servlet的生命周期方法读解,自行完成相应的动作和思考
0 读完程序中的文档,即注释,如果有相关问题,则直接回答问题。
1 注意观察页面的输出
2 注意观察console的输出
3 用插旗的方式观察程序的运行情况
4 调试程序和插旗是两种不同的思路,以后还会用日志输出来做
5 完成了一个servlet自身的访问计数器,理解一个servlet只会在容器中初始化一个实例
6 读解web.xml文件节点的顺序
7 客户端请求一个servlet[也就是激活这个servlet]的方法,测试一个servlet的方法
8 观察在eclipse下构建一个dynamic web project的目录结构
</pre>
就是通过不同的浏览器访问, 对于这个没有实现上下文的Servlet, 你会发现里面的全局变量count
在不同的浏览器中都是保存数据的, 共用的
在edge浏览器中:
在chrome浏览器中:
由此验证了, Servlet是单例的!
web.xml文件中的文件节点的读解顺序:
<web-app>
<display-name></display-name>定义了WEB应用的名字
<description></description> 声明WEB应用的描述信息
<context-param></context-param> context-param元素声明应用范围内的初始化参数。
<filter></filter> 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。
<filter-mapping></filter-mapping> 一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。
<listener></listener>servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。
<servlet></servlet> 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。
<servlet-mapping></servlet-mapping> 服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName.但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。
<session-config></session-config> 如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。 可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值。
<mime-mapping></mime-mapping>如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,则mime-mapping元素提供这种保证。
<welcome-file-list></welcome-file-list> 指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件。
<error-page></error-page> 在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面。
<taglib></taglib> 对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置,而不用编辑使用这些文件的JSP页面。
<resource-env-ref></resource-env-ref>声明与资源相关的一个管理对象。
<resource-ref></resource-ref> 声明一个资源工厂使用的外部资源。
<security-constraint></security-constraint> 制定应该保护的URL。它与login-config元素联合使用
<login-config></login-config> 指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。
<security-role></security-role>给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。
<env-entry></env-entry>声明Web应用的环境项。
<ejb-ref></ejb-ref>声明一个EJB的主目录的引用。
<ejb-local-ref></ejb-local-ref>声明一个EJB的本地主目录的应用。
</web-app>
更详细的web.xml配置[web.xml文件详解 - 生活是很好玩的 - 博客园 (cnblogs.com)](https://www.cnblogs.com/Andrew-Zhou/p/13394190.html#:~:text=那么,web项目启动时,可以知道web.xml文件各个节点的加载顺序:context-param -> listener ->,filter -> servlet 2.2 web.xml中定义的元素)
第5个war包:
实验的相关要求:
<pre>
自行完成相应的动作和思考
1 读完程序中的文档,即注释,如果有相关问题,则直接回答问题。1 利用上下文对象获取服务器上的文件里的数据
2 计数器的累计操作是如何实现的
3 在生命周期函数里的初始化函数中做一些Servlet的准备工作
</pre>
计数器的累计操作是,通过全局变量count,在每一次访问doget方法时,对count进行自加一
发现了一个问题,就是同时对同一个文件进行写入读取,会读不出来数据,也写不进去数据
暂时没找到解决方案,
如果只进行写入操作,就能
getClass().getResourceAsStream()的
和张zh讨论后发现, 是在doget方法对生成的count.txt文件路径写错了, servlet没有找到, 就报了空指针异常!
doget方法:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
InputStream is = new FileInputStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String string = br.readLine();
System.out.println("读到的字符串是:" + string);
this.count = Integer.parseInt(string);
br.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
count++;
out.println("这个Servlet历史上已经被访问了"+count+"次了!");
System.out.println("这个Servlet历史上已经被访问了"+count+"次了!");
OutputStream fw = new FileOutputStream(path);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fw));
String string = String.valueOf(count);
bw.write(string);
bw.close();
fw.close();
System.out.println("该Servlet的doGet方法被执行了一次");
}
在每次请求中对count.txt进行读写操作!成功!
第6个war包:
实验相关要求:
<pre>
自行完成相应的动作和思考
1.读完程序中的文档,即注释,如果有相关问题,则直接回答问题。
1.1 利用上下文对象获取服务器上的文件里的数据
2 计数器的累计操作是如何实现的
3 在生命周期函数里的初始化函数中做一些Servlet的准备工作
4 注意web项目中的IO操作,在读写文件之前,要定位文件所在的位置。
4.1 用class文件反射得到的是包下的路径
count.txt发布以后仍然在WEB-INF目录下
countinpackage.txt发布后,跟随.java文件生成的.class文件位置
4.2 真实的项目发布时的路径,一般置于资源文件下,以后可以用maven来管理
4.3 在tomcat下直接测试时,是一个临时目录
.metadata/.plugin/
在这个目录下才看得到发布的项目
D:\eclipse_workspace_20192\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps
4.4 在发布以后,包名会转化为一层层的目录
cn.edu.cuit.servlet即cn/edu/cuit/servlet
</pre>
不知道为甚会出现,没有生成:countinpackage.txt
后面经过张zh的提醒想到了, 这是maven compile的时候对资源文件扫描不全的原因造成的!
在maven中build加上这个:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.txt</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.txt</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
在这个过程中发现了一个问题! 就是, 通过回车
和刷新
有不同的效果
直接刷新页面就会有重新提交表单的小窗提示:
第7个war包:
实验相关要求:
<pre>
自行完成相应的动作和思考
0.读完程序中的文档,即注释,如果有相关问题,则直接回答问题。
Servlet的对象参数的作用域
1 request-Request对象
2 session-HttpSession对象
3 application-ServletContext对象
在项目中,页面之间或是请求之间会发生跳转,跳转过后,数据还可不可见,能不能传递过去,用户心里要清楚。
1 Servlet与Servlet之间
2 Servlet与JSP之间
3 JSP与JSP之间
注意路径,特别是相对路径
</pre>
第一个业务:对数字进行相应的处理:
servlet之间的转发:
// 转发给另一个Servlet来处理
request.getRequestDispatcher("operTwoServlet").forward(request,response);
...
// 获取上下文域中的参数
String msg=(String)sc.getAttribute("msg");
第二个业务:
主要通过上下文进行数据共用
ServletContext sc; //APP全局可见
先进入管理员页面输入自己想要广播的信息:
http://localhost:8080/07/servletContextParam/admin.html
然后进入首页:
点击链接即可:
对日期字符串格式的处理:
// 对日期字符串格式的处理
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 获取当前系统时间
String date=simpleDateFormat.format(new Date());
第三个业务:
输入相应的url
添加了商品后会发现:有中文乱码(暂时无解决方案)
经过评论区友友的提醒, 把product的编码给去掉就行
执行流程:
表单提交到servlet上
<!-- 以下有两个form,请求的URL是不一样的 -->
<form action="../addServlet" name="form1">
输入您要购买的产品名称:<br>
<input type="text" name="product">
<input type="submit" value="添加购物车">
</form>
<form action="../shoppingServlet" name="form2">
<input type="submit" value="查看购物车">
</form>
对于一次会话, 都会新建一个session对象:
session对象中存有shopping(这里代指购物车里面的东西)
// 配置输出参数
response.setContentType("text/html;charset=utf-8");
// 输出对象,即开流
PrintWriter out=response.getWriter();
// 创建session对象,即创建会话
HttpSession session=request.getSession();
// 获取参数,强转为相应的类型,更方便使用
String product=(String)request.getParameter("product");
String shopping=(String)session.getAttribute("shopping");
// 设置参数的编码,避免中文乱码
String newproduct=new String(product.getBytes(),"utf-8");
if(shopping==null) // 首次,肯定是null状态
{
//设置session域的属性参数值
session.setAttribute("shopping",newproduct);
}
else
{
String str=shopping+"<br>"+newproduct;
session.setAttribute("shopping",str);
}
out.println("产品已添加至购物车中!");
-
Servlet与Servlet之间(8条消息) 五、Servlet之间的交互_FrankLLN的博客-CSDN博客_servlet交互
-
Servlet与JSP之间:(8条消息) Servlet和JSP的交互方式_代码浪人的博客-CSDN博客_jsp与servlet数据的交互
主要是通过提交表单的方式给servlet传输数据
注意相对路径
<form action="../adminServlet"> 输入系统消息: <input type="text" name="msg"> <input type="submit" value="发布"> </form>
END
上机war作业(上)就暂且做到这里
欢迎点赞关注哦!
也欢迎到访我的博客!
同样欢迎友链互加!
小小的博客传送门!