一、javaweb服务器
1.1、服务器
就是一段应用程序,类似于是一个装代码的容器。我们可以将可执行的代码放到这存放到容器中,当用户向服务器发送请求时,服务器就会自动去根据请求调用对应的代码来执行。
1.2、服务器的种类
apatch nginx iis **tomcat**。
tomcat:使用java语言开发的服务器。
1.3、tomcat安装
步骤:
1、将压缩包解压到无中文无空格的目录下即可。
2、配置环境变量
3、将mysql的驱动包放在lib目录中
tomcat目录
bin: 可执行的脚本
conf : tomcat配置文件所在的目录
lib: tomcat运行过程中需要使用到的第三方依赖所在的目录
logs: tomcat运行时产生的日志文件所在的目录
temp: tomcat运行时产生的临时文件存储目录
webapps: web项目的部署目录
work: 项目的工作目录
二、WEB项目的常见架构
2.1、CS
c:client(客户端)
s:server(服务端)
特点是:如果客户需要使用系列的话,需要先下载客户端才可以使用。
优点:客户端和服务器都是同一家公司开发的,客户端与服务端的数据交互时可以直接使用自己定义的格式,
缺点:客户端比较庞大时,下载时非常耗费资源,网络不好时,无法完成下载。。。。。。
2.2、BS
b:browser
s:server
特点时:无需下载专用的客户端,直接使用浏览器来代替客户端。
优点:不耗费资源
缺点:浏览器与服务端进行数据交互时,服务端无法直接处理浏览器发送过来的数据。
三、协议
用于规范浏览器和服务端数据交互的格式。
3.1、HTTP协议:
超文本传输协议 hyper text transfer protocal,是一个简单的请求-响应协议。
HTTP请求格式
请求行 :
请求头:以键值对的形式出现
空行
请求正文:
GET:没有请求正文,原因是用户提交的参数会拼接在URL上,再传递到后台服务器。
POST:就会存在请求正文。
HTTP响应格式
响应状态码
常见错误响应状态码
400-499 客户端错误响应
- 400 Bad Request: 请求语法有问题,服务器无法识别:没有host请求头字段,或者设置了超过一个的host请求头字段。
- 401 UnAuthorized: 客户端未授权该请求。缺乏有效的身份认证凭证,一般可能是未登陆。登陆后一般都解决问题。
- 403 Forbidden: 服务器拒绝响应。权限不足。
- 404 Not Found: URL无效或者URL有效但是没有资源。
- 405 Method Not Allowed: 请求方式Method不允许。
- 406 Not Acceptable: 资源类型不符合服务器要求。
- 407 Proxy Authorization Required: 需要代理授权。
- 408 Request Timeout:服务器将不再使用的连接关闭。响应头会有Connection: close。
426 Upgrade Required: 告诉客户端需要升级通信协议。
500-599 服务器错误响应
500 Internal Server Error: 服务器内部错误,未捕获。
- 502 Bad Gateway: 服务器作为网关使用时,收到上游服务器返回的无效响应。
- 503 Service Unavailable: 无法服务。一般发生在因维护而停机或者服务过载。一般还会伴随着返回一个响应头Retry-After: 说明恢复服务的估计时间。
- 504 Gateway Timeout: 网关超时。服务器作为网关或者代理,不能及时从上游服务器获取响应返回给客户端。
- 505 Http Version Not Supported: 发出的请求http版本服务器不支持。如果请求通过http2发送,服务器不支持http2.0,就会返回该状态码。
3.2、URI和URL
URI:统一资源标识符
作用:用于标识互联网上的某一份资源的名称
ftp://资源名称
public://资源名称
public://a.png
URL:统一资源定位符
URL是URI的子集,比URI更为强大。不光可以标识资源名称,还指定了访问对应资源的路径。
标准的URL: http://192.168.120.136:8098/a.png
ip+port是可以定位一台设备上某个应用程序。
ip:用于唯一标识互联网上的物理设备
port:用于确定设备上的应用程序
四、入门案例
如何在idea中创建web项目?
4.1、servlet
web项目的三大组件之一
三大组件:servlet(重点) filter listener
作用:接收请求,作出响应。
Servlet是一个接口,该接口有一个实现类GenericServlet,GenericServlet有一个子类HttpServlet(重点)
创建servlet的步骤:
1、创建一个类,继承HttpServlet
2、重写service()
public class LoginServlet extends HttpServlet {
// @Override
// protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("do something .......");
// }
// @Override
// protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//// doGet(req,resp);
// System.out.println("do something .......");
// }
/**
* 重写service(),可以处理任何类型的请求方式
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.service(req, resp);
System.out.println("do something .......");
}
}
3、在web.xml中配置servlet
<!--servlet的配置-->
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.woniuxy.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<!-- http://localhost:8080/login -->
<url-pattern>/login</url-pattern>
</servlet-mapping>
servlet的三种创建方式
1、继承HttpServlet
2、实现servlet接口
package com.woniuxy.servlet;
import javax.servlet.*;
import java.io.IOException;
public class ServletInterface implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("实现了servlet接口创建的servlet在处理请求");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
3、继承GenericServlet
public class ServletExtendsGenericServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("ServletExtendsGenericServlet do something ....");
}
}
url-pattern的配置
<!--
url-pattern用于匹配url中除去协议+ip+端口之后的内容
url-pattern的值编写时,可以使用*通配符
如果使用通配符,请注意*只能出现在最前或最后,不能出现在中间
url-pattern的值编写方式有三种:精确匹配、前缀匹配、后缀匹配
精确匹配:/user
前缀匹配:/user/*
后缀匹配:*.do
匹配所有:/* 这种写法在servlet中是不会这么用的。
url-pattern可以配置多个
-->
<url-pattern>*.do</url-pattern>
生命周期
servlet的生命周期:
init():在servlet初始化时执行
destroy():在servlet销毁的时候执行
service():在servlet接收到请求时执行的
servlet的生命周期基于load-on-startup的配置与否,决定servlet初始化时机。
如果不配置,则servlet在第一次接收用户请求时,完成初始化
如果配置了,则在tomcat启动时,servlet就完成了初始化
load-on-startup的配置位置:在
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.woniuxy.servlet.LoginServlet</servlet-class>
<!--<load-on-startup>的取值是非零整数,值越小,越先初始化-->
<load-on-startup>1</load-on-startup>
</servlet>
servletConfig
getServletConfig()用于获取当前servlet的配置信息对象ServletConfig,每个ServletConfig对象都代表当前servlet在web.xml文件中的配置信息,调用该对象的相应方法可以不必进行XML解析而直接获取对应配置信息。
ServletConfig
ServletConfig是一个接口,有4个方法:
- getServletName():获取
中的内容; - getServletContext():获取servlet上下文;
- getInitParameter(String name):获取servlet初始化参数,与
对应; - getInitParameterNames():获取所有初始化参数名称,返回的是一个集合(迭代器)。
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.woniuxy.servlet.LoginServlet</servlet-class>
<!--<load-on-startup>的取值是非零整数,值越小,越先初始化-->
<init-param>
<param-name>a</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<param-name>b</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
public class LoginServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("LoginServlet被初始化了");
}
@Override
public void destroy() {
System.out.println("LoginServlet被销毁了");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.service(req,resp);
// System.out.println("do something......");
//获取servletConfig对象
ServletConfig config = getServletConfig();
//获取servlet名称
System.out.println(config.getServletName());
//根据param-name的值去获取param-value
System.out.println(config.getInitParameter("a"));
//获取所有param-name的值
Enumeration<String> initParameterNames = config.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
String paramName = initParameterNames.nextElement();
System.out.println(config.getInitParameter(paramName));
}
}
}
解决控制台乱码:
4.2、HttpServletRequest
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/login" method="post">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="立即登录">
</td>
</tr>
</table>
</form>
</body>
</html>
从请求行中获取数据
//获取请求行中的内容
//返回的是请求的提交方式
String method = req.getMethod();
System.out.println(method);
//获取协议
String scheme = req.getScheme();
System.out.println(scheme);
//获取请求URI
String requestURI = req.getRequestURI();
System.out.println(requestURI);
//获取请求的URL
StringBuffer requestURL = req.getRequestURL();
System.out.println(requestURL.toString());
从请求头中获取数据
//根据头的key去获取值
String s = req.getHeader("Host");
System.out.println(s);
//获取所有请求头中的key
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println(req.getHeader(headerName));
}
获取用户传递的参数(重点掌握)
//根据表单控件的name属性值或者url中?传参的参数名去获取对应的值
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+":"+password);
4.3、HttpServletResponse
对响应对象进行相应的设置
package com.woniuxy.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class TestResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//HttpServletResponse响应对象
//设置响应状态码
// resp.setStatus(400);
//响应错误码
//resp.sendError(400);
// resp.sendError(400,"类型转换错误");
//设置响应内容的类型
resp.setContentType("text/html;charset=utf-8");
//获取输出流
PrintWriter writer = resp.getWriter();
//通过输出流向浏览器写出内容
writer.write("<h1>今天的天气真的不错,又不热又不冷。</h1>");
//设置响应头信息,使用setHeader()对同一个key进行添加时,会覆盖
resp.setHeader("a","1");
resp.setHeader("a","2");
resp.setHeader("a","3");
resp.setHeader("a","4");
//添加响应头信息,使用addHeader()对同一个key进行添加时,不会覆盖
resp.addHeader("a","5");
resp.addHeader("a","6");
resp.addHeader("a","7");
resp.addHeader("a","8");
resp.setHeader("a","9");
}
}
4.4、BaseServlet
/**
* 1、从请求参数中获取method的值
* 2、根据method的值通过反射API生成Method对象
* 3、调用invoke执行对应的方法,并对方法的返回值进行不同的处理。(指定不同的跳转方式)
*/
public class BaseServlet extends HttpServlet {
/**
* 假设请求的发送方式是:http://localhost:8080/user?mehtod=register
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String methodName = req.getParameter("method");//null ""
System.out.println(methodName);
if (null==methodName||"".equals(methodName)) {//用户未传递method参数或method参数未给值
throw new RuntimeException("请求中未传递method参数,后台无法调用具体的方法来处理您的业务!");
}
try {
//this:请求访问的是哪个servelt,这个this就是该servlet的对象
Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
Object returnValue = method.invoke(this, req, resp);
//对于返回值来说,如果为null,表示方法没有返回值(ajax)
if (null==returnValue) {//对ajax请求的处理
return ;
}
String methodReturnValue = (String) returnValue;
if (methodReturnValue.contains(":")) {//如果返回值中有:存在,表示指定了跳转方式
String[] values = methodReturnValue.split(":");
String operation=values[0];//跳转方式
String path=values[1];//跳转路径
if (operation.equals("r")) {
resp.sendRedirect(path);
} else if (operation.equals("f")) {
req.getRequestDispatcher(path).forward(req,resp);
}else{
throw new RuntimeException("您指定的跳转方式本系统尚不支持!!!");
}
}else{//如果没有,使用默认的跳转方式
resp.sendRedirect(methodReturnValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用BaseServlet的要点:
4.5、JSP
java servlet pages,java服务端页面。本质上来说,JSP就是一个servlet。
jsp的执行原理:

JSP页面中可以出现的哪些内容:
html css js image java(小脚本、声明、注释、表达式…..)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
div{
width: 200px;
/*height: 200px;*/
}
</style>
</head>
<body>
<!--
html注释
在jsp页面中要编写java语句,应该使用以下的几种形式:
-->
<%--
jsp注释: 在jspServlet解析相应的jsp文件时,jsp注释是不会被解析的。
--%>
<script>
// var msg="abc";
</script>
<%--小脚本 : _jspService(){} --%>
<%
int i=0;
System.out.println(i);
%>
<%-- 表达式: 语法:<%= %> --%>
<%=i%>
<%-- 声明:语法:<%! %> 写在声明中的内容会以类的成员的形式出现--%>
<%!
int x=1;
public String getString(){
return "今天星期一";
}
%>
<%=getString()%>
</body>
</html>
jsp指令
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.woniuxy.domain.User" %>
<%@ include file="jspStudy.jsp"%>
<%-- 引入JSTL --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- jsp页面中可以出现三种指令:page include taglib --%>
<%--
page指令
作用:用于对当前页面进行对应的一些设置。
语法:<%@ page 参数列表 %>
contentType:设置jsp页面的内容类型
language:表示支持的语言
pageEncoding:设置页面的字符编码集
import:导包
isELIgnored:用于指定当前JSP页面是否忽略EL表达式,
一般情况下不会设置它,当页面中的EL表达不生效时,需要手动来指定
--%>
<%
User user = new User();
%>
<%--
include指令
作用:用于引入外部资源
语法:<%@ include 参数列表 %>
--%>
<%--
taglib指令
作用:用于引入标签库,一般会使用该指令引入jtsl
语法:<%@ taglib 参数列表 %>
--%>
<c:out value="今天星期一,明天星期二"/>
</body>
</html>
4.6、EL表达式:
expression language:表达式语言。
语法:${},**作用:用于从作用域对象中获取值。**
四大作用域
作用域对象:jsp有四大作用域对象
域对象 | 内置对象 |
---|---|
pageScope | pageContext |
requestScope | request |
sessionScope | session |
applicationScope | application |
jsp的九大内置对象:
JSP九大内置对象
内置对象就是由JSP页面转译成的servlet的_jspService()方法中存在的几个对象。
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
......
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
......
9大内置对象包括_jspService()的两个参数request和response,以及_jspService()方法中的pageContext、session、application、config、out、page和异常对象Exception。
**pageContext**
pageContext是页面上下文对象,封存了其他内置对象,封存了当前JSP的运行信息。每个JSP文件单独拥有一个pageContext对象,只在当前页面有效。
//通过pageContext对象调用对应的get***()方法可以获取其他内置对象。
pageContext.getServletContext();
**session**
session对象用来存储用户的不同请求的共享数据的。该对象可以通过page指令控制是否获取。
**application**
application就是ServletContext对象,一个项目只有一个。存储用户共享数据的对象,并完成其他操作。
**config**
config就是ServletConfig,主要是用来获取web.xml中的配置数据,完成一些初始化数据的读取。
**out**
out是响应对象,Jsp内部使用。带有缓冲区的响应对象,效率高于response对象。
**page**
page代表当前JSP的对象。
**request**
request存放了当前请求数据的对象。由tomcat服务器创建。一次请求
**response**
response是响应对象,用来响应请求处理结果给浏览器的对象。设置响应头,重定向。
**exception**
exception是异常对象,存储了当前运行的异常信息。
<%@ page import="com.woniuxy.domain.User" %>
<%@ page import="java.util.Arrays" %>
<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--
el表达式:是用于从作用域对象中取值
如果不指定作用域对象去获取,此时会从最小的域逐级向上查找,
直到找到为止,如果到最后都没有找到,返回空字符串""
作用域范围由小及大:
页面域(pageScope)<请求域(requestScope)<会话域(sessionScope)<应用域(applicationScope)
如果指定作用域获取,那么只在当前域中查找,没找到时直接返回"",不会向更大的域中去查找了。
--%>
<%
//向请求对象中保存了一个用户对象
// request.setAttribute("user",new User("tom","111"));
session.setAttribute("user",new User("jack","222"));
request.setAttribute("nums", Arrays.asList(1,2,3,4));
HashMap<String, String> map = new HashMap<>();
map.put("a","1");
map.put("b","2");
map.put("c","3");
session.setAttribute("map",map);
%>
${requestScope.user.username}
<%--
el表达式的运算符: . []
“.”:如果域中存储的是某个类的对象,此时可以使用.运算符直接获取该类型的成员变量中存储的值
“[]”:一般对应于集合元素的访问
--%>
<hr>
${nums[2]>10}
<hr>
${map["a"]}
</body>
</html>
4.7、JSTL
JSTL(Java server pages standarded tag library,即JSP标准标签库)
使用条件:
1、导入相应的jar包:jstl.jar, standard.jar
2、在jsp页面中,需要通过taglib指令引入jstl
<%@ taglib prifex="c" uri="http://java.sun.com/jsp/jstl/core"%>
作用:
使用JSTL可以解决jsp页面中出现大量java代码导致可读性差的问题,使用了JSLT之后,jsp页面中就不会出现java代码,全部以标签的形式进行展示。
JSTL常用的标签:
<%@ page import="com.woniuxy.domain.User" %>
<%@ page import="java.util.Arrays" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--jstl常用标签:--%>
<%--c:set:作用:用于修改域对象中存储的对象的属性值--%>
<%
request.setAttribute("user",new User("tom","111"));
request.setAttribute("nums", Arrays.asList(1,2,3,4,5,6));
%>
<c:set target="${user}" property="username" value="jack"/>
<c:out value="${user.username}"/>
<hr>
<%--
c:if:类似于java中的if
--%>
<c:if test="${user.username.equals('tom')}">
<c:out value="${user.username}"/>
</c:if>
<%--
c:choose(switch)\c:when(case)\c:otherwise(default):类似于java中的switch
--%>
<hr>
<c:choose>
<c:when test="${user.username.equals('tom')}">
<c:out value="${user.username}"/>
</c:when>
<c:when test="${user.username.equals('jack')}">
<c:out value="${user.username}"/>
</c:when>
<c:otherwise>
<c:out value="cici"/>
</c:otherwise>
</c:choose>
<%--
c:foreach:遍历
items:要被遍历的集合
var:每次遍历从集合中获取的对象
begin:从集合的哪个位置开始
end:遍历到集合的哪个位置结束
for(int i=0;i<nums.size();i++){
nums.get(i)
}
--%>
<hr>
<c:forEach items="${nums}" var="num" begin="0" end="${nums.size()}">
<c:out value="${num}"/>
</c:forEach>
<hr>
<%--
c:remove:移除域对象中key
--%>
<c:remove var="user"></c:remove>
<c:out value="${user.username}"/>
<hr>
<%--
c:redirect:重定向
--%>
<%-- <c:redirect url="login.jsp"></c:redirect>--%>
<hr>
<c:url value="/page/a.jsp"></c:url>
</body>
</html>
4.8、过滤器
web项目三大组件之一,执行在servlet之前。
应用场景:登录验证,统一字符编码设置,敏感字符过滤,权限验证等。
过滤器生命周期与tomcat保持一致,tomcat启动时会调用filter的init方法,关闭时调用destroy方法。
创建过滤器需要实现javax.servlet.Filter接口
/**
* 实现了Filter接口的类,就会成为一个过滤器
*/
public class FirstFilter implements Filter {
/**
* 过滤器初始化时执行的方法
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器被初始化了");
}
/**
* 过滤器执行过滤的方法
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//做一些逻辑处理,基于处理的结果决定请求要不要放行,如果放行,请求就会进入servlet中去
//filterChain.doFilter(servletRequest,servletResponse);//放行
}
/**
* 过滤器销毁时执行的方法
*/
@Override
public void destroy() {
System.out.println("过滤器被销毁了");
}
}
配置过滤器
<!--配置过滤器-->
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>com.woniuxy.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/user</url-pattern>
</filter-mapping>
也可以使用@WebFilter注解完成过滤器配置
@WebFilter("/user")
登录验证
登录验证分为两种场景:
1、未登录时,不允许访问系统中的任何资源
2、未登录时,不允许访问系统中的特定资源
两种不同场景下,登录验证的实现是不同的。
登录验证的实现:
1、登录成功时,通过session保存登录状态
2、在过滤器中通过session获取登录状态,如果值为空,表示未登录,应重定向到登录页面,不为空,放行请求即可。
验证特定资源需要登录:
/**
* 登录验证的过滤器
* url-pattern应该如何配置?
* 对于静态资源是不必进行登录验证的,登录验证的是动态资源。
*
*
* 验证的是特定资源需要登录
*
*
*/
@WebFilter({"/cart.do","/order.do"})
public class LoginFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
Object isLogin = request.getSession().getAttribute("isLogin");
if (null == isLogin) {//为空,表示未登录
response.sendRedirect("/login.jsp");
} else {
filterChain.doFilter(request, response);//如果有登录状态,则直接放行
}
}
@Override
public void destroy() {
}
}
验证所有资源需要登录:
/**
* 登录验证的过滤器
* url-pattern应该如何配置?
* 对于静态资源是不必进行登录验证的,登录验证的是动态资源。
*
*
* 验证所有资源都需要登录
*
*
*/
//@WebFilter({"*.jsp","*.do"})
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//进行登录验证
//有一些特定的资源是应该直接放行的:login.jsp user.do
String requestURI = request.getRequestURI();//user.do
if ("/login.jsp".equals(requestURI)||"/register.jsp".equals(requestURI)) {//如果访问的是login.jsp,则直接放行
filterChain.doFilter(request,response);
} else if ("/user.do".equals(requestURI)) {
String method = request.getParameter("method");
if (method.equals("login") || method.equals("register")) {
filterChain.doFilter(request,response);
}else{
checkLoginStatus(request,response,filterChain);
}
}else {
checkLoginStatus(request,response,filterChain);
}
}
public void checkLoginStatus(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws IOException, ServletException {
//其余的资源就应该进行登录验证:
// 从session中去获取登录状态,如果登录状态存在,则放行,如果不存在,则重定向到登录页面。
Object isLogin = request.getSession().getAttribute("isLogin");
if (null == isLogin) {//为空,表示未登录
response.sendRedirect("/login.jsp");
} else {
filterChain.doFilter(request, response);//如果有登录状态,则直接放行
}
}
@Override
public void destroy() {
}
}
统一字符编码的设置
web.xml
<filter>
<filter-name>charsetFilter</filter-name>
<filter-class>com.woniuxy.filter.CharsetFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charsetFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器charsetFilter
public class CharsetFilter implements Filter {
private String encoding;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String encoding = filterConfig.getInitParameter("encoding");
if (null==encoding||"".equals(encoding)) {
encoding="utf-8";
}
this.encoding=encoding;
}
/**
* 字符编码设置
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//进行字符编码设置
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
//不是固定的东西,基于请求的方式进行不同的设置,今后如果发送的是ajax请求,这里的代码需要进行对应的修改。
response.setContentType("text/html;charset="+encoding);
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
filter链的执行顺序
在开发过程中,建议:每个过滤器处理自己的逻辑即可,不要让过滤器存在依赖关系。
如果需要指定过滤器的执行顺序,根据过滤器的配置方式,有不同的设置。
1、web.xml
过滤器链的执行顺序由filter-mapping的配置顺序决定
2、注解配置
过滤器链的执行顺序由filtername的字母顺序来决定
敏感字符过滤
1、设定一些敏感词汇
2、请求中所有的用户提交的参数都应该进行敏感词汇的过滤
过滤器
@WebFilter("/word")
public class WordFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//过滤请求参数的数据
//1、设定敏感词汇
List<String> words = Arrays.asList("sb","操","妈");
//2、从请求中获取所有用户提交的参数
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
Enumeration<String> parameterNames = request.getParameterNames();
//创建一个集合,用于保存进行了过滤之后的干净的字符串
ArrayList<String> newStrs = new ArrayList<>();
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
String parameter = request.getParameter(parameterName);
// 操场 妈妈叫你回家吃饭 好好学习
for (String word : words) {
if (parameter.contains(word)) {
parameter = parameter.replace(word, "***");
}
}
newStrs.add(parameter);
}
request.setAttribute("newStrs",newStrs);
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
servlet
@WebServlet("/word")public class WordServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { List<String> newStrs = (List<String>) req.getAttribute("newStrs"); System.out.println(newStrs); }}
4.9、listener(不是重点内容)
web三大组件之一,又称之为监听器。
作用:用于监听域对象(除pageContext以外)的创建和销毁,以及域对象当中的属性变化。
监听器分类:
第一类:监听域对象(除pageContext以外)的创建和销毁
第二类:监听域对象当中的属性变化 :setAttribute() removeAttribute()
req.setAttribute(“name”,”tom”) 对一个key的第一次赋值,对属性中进行新增操作
req.setAttribute(“name”,”jack”) 对同一个key的第二次或更多次赋值时,对属性进行修改操作
req.removeAttribute(“name”) 删除一个key,删除的属性
第三类:监听session域中的javaBean的属性变化。 仅作了解。
创建监听器
1、创建类,实现对应的监听器接口。
2、复写方法
3、配置监听器
第一类监听器
package com.woniuxy.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 监听域对象的创建和销毁的
*/
@WebListener
public class MyListener implements HttpSessionListener, ServletRequestListener, ServletContextListener {
/**
* session对象创建时,执行sessionCreated
* @param httpSessionEvent
*/
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("session被创建了");
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("session被销毁了");
}
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
}
}
第二类监听器
package com.woniuxy.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
/**
* 监听域对象属性的变更
*/
@WebListener
public class AttributeListener implements HttpSessionAttributeListener, ServletRequestAttributeListener, ServletContextAttributeListener {
/**
* session对象第一次调用setAttribute()对某个key进行赋值操作时,监听器调用attributeAdded
* @param httpSessionBindingEvent
*/
@Override
public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("attributeAdded");
}
/**
* session对象调用removeAttribute()对某个key进行移除操作时,监听器调用attributeRemoved
* @param httpSessionBindingEvent
*/
@Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("attributeRemoved");
}
/**
* session对象第二次或更多次调用setAttribute()对某个key进行赋值操作时,监听器调用attributeReplaced
* @param httpSessionBindingEvent
*/
@Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("attributeReplaced");
}
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
}
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
}
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
}
@Override
public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
}
}
监听器应用:
统计在线人数
创建监听器,实现httpsessionlistenter(统计在线人数增长)、servletcontextlistener(创建一个保存在线人数的变量)
统计在线登录人数
@WebListener
public class CountOnlineUser implements HttpSessionListener, ServletContextListener, HttpSessionAttributeListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//servletcontext对象初始化时,向servletContext对象中保存一个存放在线人数的变量。
ServletContext context = servletContextEvent.getServletContext();
context.setAttribute("onlineUserNum",0);//在线人数
context.setAttribute("onlineLoginUserNum",0);//在线登录人数
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
//从servletcontext对象获取在线人数的变量,并对其进行自增操作,然后重新设置回去
ServletContext context = httpSessionEvent.getSession().getServletContext();
Integer onlineUserNum = (Integer) context.getAttribute("onlineUserNum");
context.setAttribute("onlineUserNum",++onlineUserNum);
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
}
/**
*
* @param httpSessionBindingEvent
*/
@Override
public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
String name = httpSessionBindingEvent.getName();
if (name.equals("isLogin")) {
//在线登录人数就应该加一
ServletContext context = httpSessionBindingEvent.getSession().getServletContext();
Integer onlineLoginUserNum = (Integer) context.getAttribute("onlineLoginUserNum");
context.setAttribute("onlineLoginUserNum",++onlineLoginUserNum);
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
String name = httpSessionBindingEvent.getName();
if (name.equals("isLogin")) {
System.out.println("session中移除了isLogin");
//在线登录人数就应该减一
ServletContext context = httpSessionBindingEvent.getSession().getServletContext();
Integer onlineLoginUserNum = (Integer) context.getAttribute("onlineLoginUserNum");
context.setAttribute("onlineLoginUserNum",--onlineLoginUserNum);
}
}
@Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
}
}
4.10、ajax
Ajax:Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),本质上是一种浏览器端的技术。Ajax不是新的编程语言,而是一种使用现有标准(HTML / XHTML、CSS、JavaScript / DOM)的新方法。
作用:通过javascript域()向服务端发送请求,根据请求返回的结果,使用DOM来局部刷新部分网页。
优点:可以更方便和快速的对用户进行响应,用户体验会更好。
缺点:无法回退。
核心对象:XmlHttpRequest,请求由该对象向外发起,响应由该对象进行接收。
XmlHttpRequest的属性
XmlHttpRequest的方法
原生ajax的实现:
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div id="div" style="width: 400px;height: 400px;border: 1px solid black;"></div>
<input type="button" value="测试ajax请求" id="btn">
<script>
document.getElementById("btn").onclick=function () {
var div = document.getElementById("div");
//1、创建xmlhttprequest
var xmlHttpRequest = new XMLHttpRequest();
//2、设置请求内容
xmlHttpRequest.open("GET","/ajax.do?username=tom&password=111")
//3、发送请求
xmlHttpRequest.send(null)
//4、处理响应,通过DOM操作局部刷新网页
xmlHttpRequest.onreadystatechange=function () {
if (xmlHttpRequest.readyState == 4) {//代表请求完成
if (xmlHttpRequest.status == 200) {//根据不同的响应状态码进行不同页面刷新
div.innerText=xmlHttpRequest.responseText
}else if (xmlHttpRequest.status == 404) {
div.innerText="404"
}
}
}
}
</script>
</body>
</html>
ajaxservlet
@WebServlet("/ajax.do")
public class AjaxServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getParameter("username"));
resp.getWriter().write("58期");
}
}
jquery的ajax操作
$.ajax()
%E6%96%B9%E6%B3%95%E9%80%9A%E8%BF%87%20HTTP%20%E8%AF%B7%E6%B1%82%E5%8A%A0%E8%BD%BD%E8%BF%9C%E7%A8%8B%E6%95%B0%E6%8D%AE%E3%80%82%E8%AF%A5%E6%96%B9%E6%B3%95%E6%98%AF%20jQuery%20%E5%BA%95%E5%B1%82%20AJAX%20%E5%AE%9E%E7%8E%B0%E3%80%82#card=math&code=.ajax%28%29%E6%96%B9%E6%B3%95%E9%80%9A%E8%BF%87%20HTTP%20%E8%AF%B7%E6%B1%82%E5%8A%A0%E8%BD%BD%E8%BF%9C%E7%A8%8B%E6%95%B0%E6%8D%AE%E3%80%82%E8%AF%A5%E6%96%B9%E6%B3%95%E6%98%AF%20jQuery%20%E5%BA%95%E5%B1%82%20AJAX%20%E5%AE%9E%E7%8E%B0%E3%80%82&id=Sn2cR).ajax() 返回其创建的 XMLHttpRequest 对象。ajax() 方法用于执行 AJAX(异步 HTTP)请求。所有的 jQuery AJAX 方法都使用 ajax() 方法。该方法通常用于其他方法不能完成的请求。
$.ajax(options)
参数options为一个javascript对象,该对象的属性包含了$.ajax()方法所需要的请求设置及回调函数等信息,以键值对形式存在,所有属性都是可选的。
下面的表格中列出了可能的属性(加粗部分为常用,必须掌握):
名称 | 值/描述 |
---|---|
async | 布尔值,表示请求是否异步处理。默认是 true。 |
beforeSend(xhr) | 发送请求前运行的函数。 |
cache | 布尔值,表示浏览器是否缓存被请求页面。默认是 true。 |
complete(xhr,status) | 请求完成时运行的函数(在请求成功或失败之后均调用,即在 success 和 error 函数之后)。 |
contentType | 发送数据到服务器时所使用的内容类型。默认是:”application/x-www-form-urlencoded”。 |
context | 为所有 AJAX 相关的回调函数规定 “this” 值。 |
data | 规定要发送到服务器的数据。 |
dataFilter(data,type) | 用于处理 XMLHttpRequest 原始响应数据的函数。 |
dataType | 预期的服务器响应的数据类型。 |
error(xhr,status,error) | 如果请求失败要运行的函数。 |
global | 布尔值,规定是否为请求触发全局 AJAX 事件处理程序。默认是 true。 |
ifModified | 布尔值,规定是否仅在最后一次请求以来响应发生改变时才请求成功。默认是 false。 |
jsonp | 在一个 jsonp 中重写回调函数的字符串。 |
jsonpCallback | 在一个 jsonp 中规定回调函数的名称。 |
password | 规定在 HTTP 访问认证请求中使用的密码。 |
processData | 布尔值,规定通过请求发送的数据是否转换为查询字符串。默认是 true。 |
scriptCharset | 规定请求的字符集。 |
success(result,status,xhr) | 当请求成功时运行的函数。 |
timeout | 设置本地的请求超时时间(以毫秒计)。 |
traditional | 布尔值,规定是否使用参数序列化的传统样式。 |
type | 规定请求的类型(GET 或 POST)。 |
url | 规定发送请求的 URL。默认是当前页面。 |
username | 规定在 HTTP 访问认证请求中使用的用户名。 |
xhr | 用于创建 XMLHttpRequest 对象的函数。 |
$.ajax.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="/js/jquery-3.3.1.js"></script>
</head>
<body>
<form>
<table border="1" cellpadding="0" cellspacing="0">
<tr>
<td>用户名</td>
<td><input type="text" name="username" id="username"></td>
<td></td>
</tr>
<tr>
<td>密码</td>
<td><input type="text" name="password" id="password"></td>
<td></td>
</tr>
<tr>
<td colspan="3"><input type="button" value="立即注册" id="btn"></td>
</tr>
</table>
</form>
<script>
//需求:当用户名被输入完成后,失去光标时,则向后台发一次请求,验证当前用户名是否在数据库中存在
//如果存在,在用户名的表单控件后的td中,给用户作出提示
//onchange:表单控件内容发生了改变,并且失去了光标 onblur
$(function () {
$("#username").change(function () {
//向后台发请求,并把当前控件的value值带过去。
$.ajax({
url:"/user.do",//url:请求提交的位置
type:"GET", //type:请求提交的方式
data:{username:$("#username").val()}, // data: 提交请求时附带的数据
dataType:"text", //dataType:预期从服务器端返回的数据类型
success:function (resp) {//resp就是封装了服务器响应回来的数据
console.log(resp)
$("#username").parent("td").next().html(resp)
}
})
})
})
</script>
</body>
</html>
%E3%80%81#card=math&code=.get%28%29%E3%80%81&id=IaLvg).post()
%20%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8%20HTTP%20GET%20%E8%AF%B7%E6%B1%82%E4%BB%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%EF%BC%8C#card=math&code=.get%28%29%20%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8%20HTTP%20GET%20%E8%AF%B7%E6%B1%82%E4%BB%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%EF%BC%8C&id=iwyN1).post() 方法使用 HTTP POST请求从服务器加载数据,这两个方法是在$.ajax()方法上做的封装,相当于直接固定了TYPE属性的值。
$.get(URL,data,function(data,status,xhr),dataType)
参数 | 描述 |
---|---|
URL | 必需。规定您需要请求的 URL。 |
data | 可选。规定连同请求发送到服务器的数据。 |
function(data,status,xhr) | 可选。规定当请求成功时运行的函数。 额外的参数: data - 包含来自请求的结果数据status - 包含请求的状态(”success”、”notmodified”、”error”、”timeout”、”parsererror”)xhr - 包含 XMLHttpRequest 对象 |
dataType | 可选。规定预期的服务器响应的数据类型。 默认地,jQuery 会智能判断。 可能的类型:”xml” - 一个 XML 文档”html” - HTML 作为纯文本”text” - 纯文本字符串”script” - 以 JavaScript 运行响应,并以纯文本返回”json” - 以 JSON 运行响应,并以 JavaScript 对象返回”jsonp” - 使用 JSONP 加载一个 JSON 块,将添加一个 “?callback=?” 到 URL 来规定回调 |
$.post("/user.do",{username:$(this).val(),method:"register"},function (resp) { console.log(resp) },"json")
$.getJson()
$.getJson() 方法使用 HTTP GET请求从服务器加载数据,要求返回的值为JSON。
$.getJson(URL,data,function(data,status,xhr))
参数 | 描述 |
---|---|
URL | 必需。规定将请求发送到哪个 URL。 |
data | 可选。规定连同请求发送到服务器的数据。 |
function(data,status,xhr) | 可选。规定当请求成功时运行的函数。 额外的参数: data - 包含来自请求的结果数据status - 包含请求的状态(”success”、”notmodified”、”error”、”timeout”、”parsererror”)xhr - 包含 XMLHttpRequest 对象 |
$.getJSON("/user.do",{username:$(this).val(),method:"register"},function (resp) { console.log(resp) })
服务端响应JSON
1、导入fastJSON包
2、在程序中通过JSONObject对象的toJSONString()将对应的对象转换为json字符串。
User user = new User("jack", "222");resp.getWriter().write(new JSONObject().toJSONString(user));
MD5加密
特点1:
对同一个值进行md5加密时,得到的结果永远是相同的。
111 ==> gajoajalemhlakeyraemk
特点2:
加密结果不可逆。
package com.woniuxy.utils;import java.io.UnsupportedEncodingException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Base64;public class CommonsUtil { public static String md5(String password) throws UnsupportedEncodingException, NoSuchAlgorithmException { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] digest = md5.digest(password.getBytes("utf-8")); return Base64.getEncoder().encodeToString(digest); }}
五、项目相关功能
5.1、文件上传
开发人员可以使用Apache文件上传组件commons-fileupload来接收浏览器上传的文件,该组件由多个类共同组成,但是,对于使用该组件来编写文件上传功能的Java Web开发人员来说,只需要了解和使用以下三个类:
- ServletFileUpload:Apache文件上传组件的核心类,应用程序开发人员通过这个类来与Apache文件上传组件进行交互。
- FileItem:用来封装单个表单字段元素的数据,一个表单字段元素对应一个FileItem对象,通过调用FileItem对象的方法可以获得相关表单字段元素的数据。
FileUploadException:上传中产生的异常。
文件上传流程:
- 编写上传页面,form表单的enctype属性必须为”multipart/form-data”,提交方式必须为post;
- servlet中使用ServletFileUpload的isMultipartContent()判断请求消息中的内容是否是“multipart/form-data”类型,是则返回true,否则返回false。
- 返回结果为true,则基于DiskFileItemFactory工厂对象创建ServletFileUpload对象,并使用ServletFileUpload的parseRequest()解析请求,获取所有表单字段的数据集合List。
- 遍历数据集合,通过FileItem的isFormField()判断是否是普通表单字段,是则返回true,否则返回false(文件字段)。
如果FileItem是文件字段,使用FileItem的write()将文件写至指定存放地点即可。
在上传流程中,也可以使用ServletFileUpload的**setSizeMax**()设置上传文件大小,在上传操作完成后,一般会调用FileItem的**delete**()手动删除由于上传文件过大而产生的临时文件。
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/upload.do" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username" ><br>
密码:<input type="text" name="password" ><br>
头像:<input type="file" name="file" ><br>
<input type="submit" value="立即注册">
</form>
</body>
</html>
serlvet
@WebServlet("/upload.do")
public class UploadServlet extends HttpServlet {
/**
* 处理表单提交的数据
* 如果有文件域,就应该做文件上传的相应处理。
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException{
//先判断当前请求中是否存在文件上传
boolean isMulti = ServletFileUpload.isMultipartContent(req);
if (isMulti) {
//做文件上传相应的处理
try {
//创建ServletFileUpload对象
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
//设置最大尺寸
upload.setSizeMax(200*1024*1024);
//解析请求,为第一个表单控件生成对应的fileItem对象
List<FileItem> fileItems = upload.parseRequest(req);
//fileItem的类型
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()) {
String value = fileItem.getString("utf-8");
System.out.println(value);
}else{
//执行上传操作
//1、指定文件存储位置 文件服务器 文件系统下 web应用
File target = new File("D:\\files");
//2、处理文件的存储名称,解决同名文件被覆盖的问题
String originName = fileItem.getName();
String suffix = originName.substring(originName.lastIndexOf("."));
String uploadFileName=UUID.randomUUID().toString().replace("-","")+System.currentTimeMillis()+ suffix;
//生成要被上传的文件
File uploadFile = new File(target, uploadFileName);
fileItem.write(uploadFile);//上传
}
}
} catch (Exception e) {
e.printStackTrace();
}
}else{
//如果不是,就进行普通的表单处理
}
}
/**
* 1、将前端设置好
* form的method指定为post enctype指定为multipart/form-data
* 在表单中提供文件域 <input type="file" name="file"/>
* 2、在servlet中要去做的事情
* 2.1 先判断是否是文件上传的请求 ServletFileUpload.isMultipartContent(req)
* 2.2 返回值如果为true,表示是文件上传的请求,就需要解析请求:
* 2.2.1 创建SevletFileUpload对象,使用带参构造创建,参数为DiskFileItemFactory对象
* 2.2.2 设置上传请求的尺寸 upload.setSizeMax()
* 2.2.3 解析请求 upload.parseRequest(req)
* 2.2.4 遍历解析请求后返回的FileItem集合,使用isFormField()判断是否是文件字段(false)
* 2.2.5 如果是文件字段,进行文件上传的处理 指定文件的存储路径 处理上传文件的存储名称 fileItem.write(file)完成上传。
*/
}
5.2、javaMail
协议:SMTP(可发可收) POP3(发送) IMAP(接收)
javaMail,sun公司为了方便程序员进行邮件开发写的一套API
程序开发中关心的是发送邮件的API,接收部分由邮件服务提供商进行处理。
要实现邮件发送,在程序中需要使用到三个javaMail的API类:Message(邮件),Session(定义环境),Transport(发送邮件)
javaMail开发实现
1、开发前的准备:
1.1注册邮箱帐号并登录
1.2点击设置,开启SMTP/POP3服务并保存授权密码
2、编写代码发送邮件
public class CommonsUtil {
public static void sendMail(String sender,String password,String reciver,String subject,Object mailMsg) throws MessagingException {
//通过3个对象将邮件发送出去
//session message transport
//设置邮件发送的相关环境
Properties props = new Properties();
props.setProperty("mail.transport.protocol","SMTP");
props.setProperty("mail.host","smtp.163.com");
props.setProperty("mail.smtp.auth","true");
Authenticator authenticator=new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(sender,password);
}
};
Session session = Session.getInstance(props,authenticator);
//创建邮件对象,并设置邮件内容
MimeMessage message = new MimeMessage(session);
message.setContent(mailMsg,"text/html;charset=utf-8");//设置邮件的内容
message.setSubject(subject);//设置邮件标题
message.setRecipient(Message.RecipientType.TO,new InternetAddress(reciver));//设置收件人
message.setFrom(new InternetAddress(sender));//设置发件人
//发送邮件
Transport.send(message);
}
}
javaMail在项目中的应用:
业务层
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
public UserServiceImpl(){
userMapper= MybatisUtil.getMapper(UserMapper.class);
}
//注册成功后(即向数据库完成了新增),向用户在注册时提供的邮箱中发激活邮件
@Override
public boolean register(User user) throws MessagingException {
int i = userMapper.insertUser(user);
if (i>0) {
//注册成功,向用户的邮箱中发送激活邮件
CommonsUtil.sendMail("hjy15823115656@163.com",
"ZTDHHXXGVZBYQXJO",
user.getEmail(),
"用户激活",
"<a href='http://127.0.0.1:8080/user.do?method=active&activeCode="
+user.getActiveCode()+"'>"+user.getActiveCode()+"</a>");
return true;
}
return false;
}
//处理激活用户的业务,基于请求中传递的激活码进行数据库修改操作,将用户的状态修改为已激活
@Override
public boolean active(String activeCode) {
int i=userMapper.updateUserByActiveCode(activeCode);
if (i>0) {
return true;
}
return false;
}
}
mapper层
public interface UserMapper {
@Insert("insert into t_user(name,password,email,activeCode) values(#{name},#{password},#{email},#{activeCode})")
int insertUser(User user);
@Update("update t_user set state=1 where activeCode=#{activeCode}")
int updateUserByActiveCode(String activeCode);
}
5.3、注册按钮
验证用户名和邮箱都没有被注册才移除注册按钮的disabled属性
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="/js/jquery-3.3.1.js"></script>
</head>
<body>
<form action="/user.do" method="post">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username" id="username"></td>
<td></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"></td>
<td></td>
</tr>
<tr>
<td>电子邮箱</td>
<td><input type="text" name="email" id="email"></td>
<td></td>
</tr>
<tr>
<td colspan="3">
<input type="submit" id="register" disabled value="立即注册">
<input type="hidden" name="method" value="register">
</td>
</tr>
</table>
</form>
<script>
$(function () {
var checkUserName=false;
var checkEmail=false;
$("#username").change(function () {
$.getJSON("/user.do",{username:$(this).val(),method:"checkUserName"},function (resp) {
if (resp) {
checkUserName=true;
}else{
checkUserName=false;
}
if (checkUserName & checkEmail) {
$("#register").removeAttr("disabled")
}else{
$("#register").attr("disabled","disabled")
}
})
})
$("#email").change(function () {
$.getJSON("/user.do",{email:$(this).val(),method:"checkEmail"},function (resp) {
if (resp) {
checkEmail=true;
}else{
checkEmail=false;
}
if (checkUserName & checkEmail) {
$("#register").removeAttr("disabled")
}else{
$("#register").attr("disabled","disabled")
}
})
})
})
</script>
</body>
</html>
5.4、相关代码
Category
@Data
public class Category {
private Integer id;
private String name;
}
CategoryController
@WebServlet("/category.do")
public class CategoryController extends BaseServlet {
public void findAll(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=utf-8");
List<Category> categories = new CategoryServiceImpl().findAll();
response.getWriter().write(new JSONObject().toJSONString(categories));
}
}
CategoryServiceImpl
public class CategoryServiceImpl implements CategoryService {
private CategoryMapper categoryMapper;
public CategoryServiceImpl(){
categoryMapper= MyBatisUtil.getMapper(CategoryMapper.class);
}
@Override
public List<Category> findAll() {
return categoryMapper.findAll();
}
}
CategoryMapper
public interface CategoryMapper {
@Select("select * from t_category")
List<Category> findAll();
}
Goods
@Data
public class Goods {
private Integer id;
private String name;
private Double price;
private String image;
private Integer cid;
}
GoodsController
/**
* 处理商品相关的请求
*/
@WebServlet("/goods.do")
public class GoodsController extends BaseServlet {
public void findGoodsByCid(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setContentType("text/html;charset=utf-8");
String cid = request.getParameter("cid");
String pageNum = request.getParameter("pageNum");
Integer num=null==pageNum?1:Integer.valueOf(pageNum);
PageInfo<Goods> pageInfo=new GoodsServiceImpl().findGoodsByCid(num,Integer.valueOf(cid));
response.getWriter().write(new JSONObject().toJSONString(pageInfo));
}
// /**
// * 分页查询
// * @param request
// * @param response
// */
// public String page(HttpServletRequest request, HttpServletResponse response) throws IOException {
// response.setContentType("text/html;charset=utf-8");
// PageInfo<Goods> pageInfo = getPageInfo(request, response);
//
// HttpSession session = request.getSession();
// //如果session不存在商品分类信息,就去查询数据库,得到对应的商品分类信息
// if (null==session.getAttribute("categories")) {
// List<Category> categories = new CategoryServiceImpl().findAll();
// session.setAttribute("categories",categories);
// }
//
// session.setAttribute("pageInfo",pageInfo);
// return "r:/page/main.jsp";
//// response.getWriter().write(new JSONObject().toJSONString(pageInfo));
// }
//
// public void pageAjax(HttpServletRequest request, HttpServletResponse response) throws IOException {
// response.setContentType("text/html;charset=utf-8");
// response.getWriter().write(new JSONObject().toJSONString(getPageInfo(request,response)));
// }
//
// public PageInfo<Goods> getPageInfo(HttpServletRequest request, HttpServletResponse response){
// String number = request.getParameter("pageNum");
// String size = request.getParameter("pageSize");
// String cid = request.getParameter("cid");
// Integer pageNum = null== number ?1:Integer.valueOf(number);
// Integer pageSize = null== size ?5:Integer.valueOf(size);
// Integer id=null==cid?1:Integer.valueOf(cid);
// PageInfo<Goods> pageInfo=new GoodsServiceImpl().findByPage(pageNum,pageSize,id);
// return pageInfo;
// }
//
// public String getGoodsById(HttpServletRequest request, HttpServletResponse response){
//
// String id = request.getParameter("id");
//
// Goods goods=new GoodsServiceImpl().findById(Integer.valueOf(id));
//
// request.getSession().setAttribute("goods",goods);
//
// return "r:/page/goodsInfo.jsp";
// }
}
GoodsServiceImpl
public class GoodsServiceImpl implements GoodsService {
private GoodsMapper goodsMapper;
public GoodsServiceImpl(){
goodsMapper = MyBatisUtil.getMapper(GoodsMapper.class);
}
@Override
public PageInfo<Goods> findByPage(Integer pageNum,Integer pageSize,Integer cid) {
PageHelper.startPage(pageNum, pageSize);
List<Goods> goodsList = goodsMapper.findAll(cid);
PageInfo<Goods> pageInfo = new PageInfo<>(goodsList);
return pageInfo;
}
@Override
public Goods findById(Integer id) {
return goodsMapper.findById(id);
}
@Override
public PageInfo<Goods> findGoodsByCid(Integer pageNum,Integer cid) {
PageHelper.startPage(pageNum,3);
List<Goods> goodsList = goodsMapper.findGoodsByCid(cid);
PageInfo<Goods> pageInfo = new PageInfo<>(goodsList);
return pageInfo;
}
}
GoodsMapper
public interface GoodsMapper {
@Select("select * from t_goods where cid=#{cid}")
List<Goods> findAll(Integer cid);
@Select("select * from t_goods where id=#{id}")
Goods findById(Integer id);
@Select("select * from t_goods where cid=#{cid}")
List<Goods> findGoodsByCid(Integer cid);
}
main.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="/js/jquery-3.3.1.js"></script>
<style>
*{
margin: 0;
padding: 0;
}
li{
list-style: none;
width: 80px;
height: 160px;
border: 1px solid black;
float: left;
margin-left: 20px;
}
ul:after{
content: '';
display: block;
clear: both;
}
#categories>li{
width: 120px;
height: 60px;
border: 1px solid black;
float: left;
margin-left: 50px;
text-align: center;
line-height: 60px;
}
#categories{
width:516px;
height: 62px;
margin: 0 auto;
}
#categories:after{
content: '';
display: block;
clear: both;
}
#goodsList>div{
width: 150px;
height: 240px;
border: 1px solid black;
margin-left: 20px;
float: left;
}
#goodsList:after{
content: '';
display: block;
clear: both;
}
</style>
</head>
<body>
<%--展示商品大类信息--%>
<div id="categories"></div>
<hr>
<div id="goodsList"></div>
<div id="pagequery"></div>
<script>
$(function () {
//页面加载完成,查询到商品大类信息并将之渲染到页面中
$.getJSON("/category.do",{method:"findAll"},function (resp) {
var $categories = $("#categories");
for(var i=0;i<resp.length;i++){
//resp[i] --->category{id,name
}
var $div = $("<div cid='"+resp[i].id+"'>"+resp[i].name+"</div>");
$div.click(function () {
var cid = $(this).attr("cid");
//查询对应商品大类的商品信息
$.getJSON("/goods.do",{method:"findGoodsByCid",cid:cid},function (resp) {
var $goodsList = $("#goodsList");
var $pagequery = $("#pagequery");
$goodsList.html("")
$pagequery.html("")
for (var j=0;j<resp.list.length;j++){
var $goodsInfoDiv = $("<div><img src='/"+resp.list[j].image+"'width='150' height='200'/><p>"+resp.list[j].name+"</p><p>"+resp.list[j].price+"</p></div>");
$goodsList.append($goodsInfoDiv)
}
for (var k=1;k<=resp.pages;k++){
var $pageNum = $("<div pageNum='"+k+"' style='width: 20px;height: 20px;border: 1px solid black;border-radius: 50%;'>"+k+"</div>");
$pageNum.click(function () {
var pageNum = $(this).attr("pageNum");
$.getJSON("/goods.do",{method:"findGoodsByCid",pageNum:pageNum,cid:resp.list[0].cid},function (resp) {
var $goodsList = $("#goodsList");
$goodsList.html("")
for (var j=0;j<resp.list.length;j++){
var $goodsInfoDiv = $("<div><img src='/"+resp.list[j].image+"'width='150' height='200'/><p>"+resp.list[j].name+"</p><p>"+resp.list[j].price+"</p></div>");
$goodsList.append($goodsInfoDiv)
}
})
})
$pagequery.append($pageNum)
}
})
})
$categories.append($div);
}
})
// $("#categories>li").click(function () {
// var cid = $(this).attr("cid");
// $.getJSON("/goods.do",{method:"pageAjax",cid:cid},function (resp) {
// console.log(resp)
// var $goods = $("#goods");
// $goods.html("");
// for (var i=0;i<resp.list.length;i++){
// $goods.append("<li>" +
// " <img src='/"+resp.list[i].image+"' width='78' height='140'/>" +
// " <p>"+resp.list[i].name+"</p>\n" +
// " <p>"+resp.list[i].price+"</p>\n" + // " </li>")
// }
// })
// }) })
</script>
<%--展示某一个商品大类对应的商品信息--%>
<ul id="goods">
<c:forEach items="${pageInfo.list}" var="goods" begin="0" end="${pageInfo.list.size()}">
<li>
<%-- <a href="/goods.do?method=getGoodsById&id=${goods.id}">--%>
<img class="goodsImg" gid="${goods.id}" src="/${goods.image}" width="78" height="140"/>
<%-- </a>--%>
<p>${goods.name}</p>
<p>${goods.price}</p>
</li>
</c:forEach>
</ul>
<script>
$(function () {
$(".goodsImg").click(function () {
//sessionStorage.setItem("id",$(this).attr("gid"));//html5 web存储
location.href="goodsInfo.jsp?id="+$(this).attr("gid")
})
})
</script>
<%-- <div id="content"></div>--%>
<%-- <div id="div"></div>--%><%--<script>--%>
<%-- // $(function () {--%>
<%-- //页面加载完成,向后台发送请求:查询商品信息--%>
<%-- // $.getJSON("/goods.do",{method:"page"},function (resp) {--%>
<%-- // console.log(resp)--%>
<%-- // var $content = $("#content");--%>
<%-- // for (var i=0;i<resp.list.length;i++) {--%>
<%-- // $content.append("<span>"+resp.list[i].name+"</span>")--%>
<%-- // }--%>
<%-- // for (var j=0;j<resp.pages;j++) {--%>
<%-- // var $input = $("<input class='pageIndex' type='button' value='"+(j+1)+"'/>");--%>
<%-- // $input.click(function () {--%>
<%-- // var pageNum = $(this).val();--%>
<%-- // $.getJSON("/goods.do",{method:"page",pageNum:pageNum},function (resp) {--%>
<%-- // console.log(resp)--%>
<%-- // })--%>
<%-- // })--%>
<%-- // $("#div").append($input)--%>
<%-- // }--%>
<%-- // });--%>
<%-- // })--%>
<%--</script>--%>
</body>
</html>