JavaWeb
1、Maven
1.在javaweb开发中,需要使用大量的jar包
2.如何能够让一个东西帮我们导入和配置这个jar包
由此,Maven诞生了
1.1 Maven项目架构管理工具
我们目前就是用来方便导入jar包的
Maven的核心思想:约定大于配置
- 有约束,不要去违反
Maven会规定好你该如何去编写我们的java代码,必须按照这个规范来
1.2 下载安装Maven
https://maven.apache.org/download.cgi
1.3配置环境变量
在我们的系统环境变量中
配置如下信息:
- M2_HOME maven目录下的bin目录
- MAVEN_HOME maven的目录
- 在系统的path中配置 %MAVEN_HOME%\bin
测试maven是否安装成功:
1.4 阿里云镜像
- 镜像:Mirrors
- 作用:加速下载
- 国内建议使用阿里云镜像
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
1.5 本地仓库
在本地的仓库、远程仓库;
建立一个本地仓库:localRepository
D:\Environment\apache-maven-3.8.2\maven-repo
1.6、在IDEA中使用Maven
- 启动IDEA
- 创建一个MavenWeb项目
- IDEA自动下载一些东西
-
观察Maven仓库中的变化
-
IDEA中的Maven设置
IDEA中配置Maven,经常在IDEA中会出现一个问题:项目自动创建完成之后,它这个MavenHome会使用IDEA默认,如果发现了这个问题,需要手动修改为本地
1.7、创建一个普通的Maven项目
新建项目的时候不勾选使用maven模板
1.8、标记文件夹功能
1.9、在IDEA中配置Tomcat
解决警告问题
问题产生原因:我们访问一个网站,需要指定一个文件夹名字
虚拟路径映射
1.10 POM文件
pom.xml 是Maven的核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--Maven版本和头文件-->
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 这里就是配置的GAV-->
<groupId>org.example</groupId>
<artifactId>JavaWeb</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- package:项目的打包方式
jar:java应用
war:javaweb应用
-->
<packaging>war</packaging>
<name>JavaWeb Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<!-- 配置-->
<properties>
<!-- 项目的默认构建编码-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 编码版本-->
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<!-- 项目依赖-->
<dependencies>
<!-- 具体依赖的jar包配置文件-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 项目构建用的东西-->
<build>
<finalName>JavaWeb</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
1.11 IDEA操作
2、Servlet
在客户端无法访问WEB-INF文件中的东西
2.1、Servlet简介
- Servlet是sun公司开发动态web的一门技术
- Sun在这些API中提供了一个接口,叫做Serlvet,如果想开发一个Serlvet程序,需要以下两个步骤:
- 编写一个类,实现Serlvet接口
- 把开发好的Java类部署到web服务器中
把实现了Serlvet接口的Java程序叫Serlvet
2.2、HelloSerlvet
Servlet接口在Sun公司有两个默认实现类:HttpServlet 、 GenericServlet
1.构建一个普通的Maven项目,删除掉里面的src目录,以后就在这个项目里面新建Moudel;这个空的工程就是Maven主工程
2.关于Maven父子工程的理解
父项目会有
<modules>
<module>servlet-01</module>
</modules>
子项目会有
<parent>
<artifactId>javaweb-02-serlvet</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的java,子项目可以直接使用
son extends father
3.Maven环境优化
- 修改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_4_0.xsd"
version="4.0"
metadata-complete="true">
</web-app>
- 将maven的结构搭建完整
4.编写一个servlet程序
- 编写一个普通类
- 实现Servlet接口,这里我们可以直接继承HttpServlet
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ServletOutputStream outputStream = resp.getOutputStream();/
PrintWriter writer = resp.getWriter();//响应流
writer.print("Hello,Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
5.编写Servlet的映射
为什么需要映射:我们写的是JAVA程序,但是需要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径
<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.luo.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
6.配置Tomcat
注意:配置项目发布的路径
7.启动测试
2.3、Servlet原理
Servlet是由Web服务器调用,web服务器在收到浏览器请求之后,会:
- 一个Servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 一个Servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
- 一个Servlet可以指定通用映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
注意:/* 为默认通配符,会直接进如该项目,不会进入首页
- 指定一些后缀或者前缀等等
可以自定义后缀实现请求映射,注意:*前面不能加项目映射的路径。使用*.adminluo ,可以通过/hello/test.adminluo进入该映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.adminluo</url-pattern>
</servlet-mapping>
5.优先级问题
指定了固有的映射路径优先级最高,如果找不到,就会走默认的处理请求
实现自定义404:
web.xml:
<!--404-->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.luo.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ErrorServlet:
package com.luo.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 ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
PrintWriter writer = resp.getWriter();
writer.print("<h1>404</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.4、ServletContext
在web.xml中也可以设置context-param 【配置web应用初始化参数】
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
<!--
以键值对的方式设置参数url的值为jdbc:mysql://localhost:3306/mybatis
-->
1、共享数据
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用
-
共享数据
我在这个Servlet中保存的数据,可以在另外一个servlet中拿到,以实现数据共享
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_4_0.xsd" version="4.0" metadata-complete="true"> <servlet> <servlet-name>getc</servlet-name> <servlet-class>com.luo.servlet.GetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>getc</servlet-name> <url-pattern>/getc</url-pattern> </servlet-mapping> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.luo.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
HelloServlet (设置所要共享的数据):
package com.luo.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //this.getInitParameter() 初始化参数 //this.getServletConfig() Servlet配置 //this.getServletContext() Servlet上下文 ServletContext context = this.getServletContext(); String username = "罗"; context.setAttribute("username",username);//将一个数据保存在了ServletContext中,名字为username。值 username System.out.println("Hello"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
GetServlet (取得所要共享的数据):
package com.luo.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class GetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); String username = (String) context.getAttribute("username"); resp.setContentType("text/html;charset=utf-8"); resp.getWriter().print("名字:"+username); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
测试访问
2、获取初始化参数
-
先设置初始化参数 【在web.xml中】
<context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/mybatis</param-value> </context-param> <!-- 以键值对的方式设置参数url的值为jdbc:mysql://localhost:3306/mybatis -->
-
获取初始化参数
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); String url = context.getInitParameter("url"); resp.getWriter().print(url); }
3、请求转发
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("in demo04");
ServletContext context = this.getServletContext();
RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp"); //转发的请求路径
requestDispatcher.forward(req,resp); //调用forward实现请求方法
}
4、读取资源文件
Properties
- 在java目录新建properties
- 在resources目录新建properties
发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath;【也称为类路径】
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("WEB-INF/classes/db.properties");
Properties prop = new Properties();
prop.load(is);
String user = prop.getProperty("username");
String passwd = prop.getProperty("password");
resp.getWriter().print(user+":"+passwd);
is.close();
}
2.5、HttpServletResponse
响应:web服务器接收到客户端的http请求,会针对这个请求分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse
- 如果要获取我们客户端请求过来的参数,找HttpServletRequest
- 如果要给客户端响应一些信息,找HttpServletResponse
1、简单分类
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setBufferSize(int var1);
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
响应的状态码
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
2、下载文件
-
向浏览器输出消息
-
下载文件
中文乱码问题:
resp.setContenType("text/html"); resp.setCharacterEncoding("utf-8");
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1. 要获取下载文件的路径 String realPath = "D:\\JavaWeb\\javaweb-02-serlvet\\response\\src\\main\\resources\\1.png"; System.out.println("下载的文件路径:"+realPath); //2. 下载的文件名 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1); //3. 设置想办法让浏览器能够支持下载我们需要的东西,中文文件名URLEncoder.encode编码,否则可能会产生乱码 resp.setHeader("Contest-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")); //4. 获取下载文件的输入流 FileInputStream in = new FileInputStream(realPath); //5. 创建缓冲区 int len = 0; byte[] buffer = new byte[1024]; //6. 获取OutputStream对象 ServletOutputStream out = resp.getOutputStream(); //7. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区的数据输出到客户端 while ((len = in.read(buffer))>0){ out.write(buffer,0,len); } out.close(); in.close(); }
- 要获取下载文件的路径
- 下载的文件名
- 设置想办法让浏览器能够支持下载我们需要的东西
- 获取下载文件的输入流
- 创建缓冲区
- 获取OutputStream对象
- 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区的数据输出到客户端
-
验证码功能
- 前端实现
- 后端实现,需要用到Java的图片类,生成一个图片
验证码实现代码:
package com.luo.servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.Buffer;
import java.util.Random;
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//让浏览器3秒自动刷新一次
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g =(Graphics2D) image.getGraphics(); //笔
//设置图片的背景颜色
g.setColor(Color.white);
g.fillRect(0,0,70,20);
//给图片写数据
g.setColor(Color.BLUE);
g.setFont(new Font(null,Font.BOLD,20));
g.drawString(makeNum(),0,20);
//告诉浏览器,这个请求用图片的方式打开
resp.setContentType("image/jpeg");
//网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
ImageIO.write(image,"jpg",resp.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
private String makeNum(){
Random random = new Random();
String num = random.nextInt(9999999)+"";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 7-num.length(); i++) {
sb.append("0");
}
num = sb.toString() + num;
return num;
}
}
4、实现重定向
常见场景
-
用户登录
void sendRedirect(String var1) throws IOException;
index.jsp:
<html> <body> <h2>Hello World!</h2> <%@ page contentType="text/html; charset=UTF-8"%> <form action="${pageContext.request.contextPath}/login" method="get"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="submit"> </form> </body> </html>
RequestTest.java:
在web.xml中,指向该文件的路径为${pageContext.request.contextPath}/login 【即tomcat配置的路径/login】
package com.luo.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class RequestTest extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("进入了这个请求"); String username = req.getParameter("username"); String password = req.getParameter("password"); System.out.println(username+":"+password); resp.sendRedirect("/response_war/success.jsp"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
success.jsp:
<%-- Created by IntelliJ IDEA. User: AdminLuo Date: 2021/9/1 Time: 17:26 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page isELIgnored="false"%> <html> <head> <title>success</title> </head> <body> <h1>Success!</h1> </body> </html>
在body里面添加这个:<%@ page contentType="text/html; charset=UTF-8"%>
如果跳转失败证明jsp页面还不支持el表达式,最简单的方法是在jsp上面加上<%@ page isELIgnored="false"%>
jsp代码里面加上这些话<%@ page contentType="text/html; charset=UTF-8" %>
2.6、HttpServletRequest
1、获取前端传递的参数,并且请求转发
//以下两种用的较多
req.getParameter(String s) String
req.getParameterValues(String s) String[]
getRequestDispatcher分成两种,可以用request调用,也可以用getServletContext()调用
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobby = req.getParameterValues("hobbys");
System.out.println("===========================");
//后台接收中文乱码问题
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobby));
System.out.println("============================");
//System.out.println(req.getContextPath());
//通过请求转发
//这里的 / 代表当前web应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
重定向和转发的区别
相同点
- 页面都会实现跳转
不同点
- 请求转发的时候,url不会产生变化 307
- 重定向的时候,url地址栏会发生变化 302
3、Cookie、Session
3.1、会话
用户打开了一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话
两者的不同:
- 存储位置不同: cookie是保存在客户端, session是保存服务器端
- 存储数据量大小不同: cookie存储是有限的, 不超过4KB, seesion是无限制的;
- 存储的数据类型不同:cookie只能存储键值对的字符串类型,而session可以存储任意类型
- 默认有效期不同:cookie默认是会话级别的cookie,而session默认有效期是30分钟
3.2、保存会话的两种技术
Cookie
- 客户端技术 响应,请求
Session
- 服务器端技术,利用这个技术,可以保存用户的会话信息
Cookie
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
PrintWriter out = resp.getWriter();
//Cookie 服务器端从客户端获取
Cookie[] cookies = req.getCookies();
//判断cookie是否存在
if(cookies != null){
out.write("你上一次访问的时间是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
//获取cookie的名字
if (cookie.getName().equals("lastLoginTime")){
//获取cookie中的值
long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
out.write(date.toLocaleString());
}
}
}
else {
out.write("您这是第一次访问本站");
}
Cookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis()+"");
resp.addCookie(cookie);
//服务器端从客户端获取Cookie
}
out是jsp的内置对象
用name.equals能避免空指针异常
Session
demo03用来注销session,内容如下:【手动注销session】
还可以在web.xml中设置session默认生效时间
其是以分钟为单位
Session 和 Cookie的区别
- Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
- Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)
- Session对象由服务器创建
Session是面向单个用户的,ApplicationContext/ServletContext是面向全体用户的,一个是你自己的储物柜,一个是大院子
3、JSP
Java Server Pages:Java服务器端页面,也和Servelt一样,用于动态web技术
最大的特点:
- 写JSP就像在写HTML
- 区别
- HTML只给用户提供静态的数据
- JSP页面中可以嵌入JAVA代码,为用户提供动态数据
3.2、JSP原理
JSP到底怎么执行的
IDEA TomCat的工作空间
项目地址:
C:\Users\AdminLuo\AppData\Local\JetBrains\IntelliJIdea2021.2\tomcat\d378a619-ff6f-41d2-8537-467da81ee8df\work\Catalina\localhost\ROOT\org\apache\jsp
发现页面转变成了Java程序
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servelt
JSP最终也会转换成为一个Java类
JSP本质上就是一个Servlet
//初始化
public void _jspInit() {
}
//销毁
public void _jspDestroy() {
}
//JSPService
public void _jspService(HttpServletRequest request, HttpServletResponse response)
-
判断请求
-
内置一些对象
final javax.servlet.jsp.PageContext pageContext; //页面上下文 javax.servlet.http.HttpSession session = null; //session final javax.servlet.ServletContext application; //applicationContext final javax.servlet.ServletConfig config; //config javax.servlet.jsp.JspWriter out = null; //out final java.lang.Object page = this; //page:当前页 HttpServletRequest request,//请求 HttpServletResponse response//响应
-
输出页面钱增加的代码
response.setContentType("text/html"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
-
以上的对象可以在JSP页面中直接使用
在JSP页面中,只要是JAVA代码就会原封不动的输出;
如果是HTML代码,就会被转发为:
out.write("<html>\r\n")
这种格式,输出到前端
3.3、JSP基础语法
JSP表达式
<%--JSP表达式
作用;用来将程序的输出,输出到客户端
<%= 变量表达式%>
--%>
<%= new java.util.Date()%>
还可以使用EL表达式:
${Java代码}
JSP脚本片段
<%
int sum = 0;
for (int i = 1; i < 100; i++) {
sum+=i;
}
out.println("<h1>sum="+sum+"</h1><p>test</p>");
%>
<%
for (int i = 0; i < 5; i++) {
%>
<h1>helloworld <%=i%></h1>
<%
}
%>
JSP声明
<%!
static {
System.out.println("Loading Servlet");
}
private int globalVar = 0;
public void test(){
System.out.println("进入了方法test!");
}
%>
JSP声明:会被编译到JSP生成的Java类中,其他的会被生成到_jspService方法中
在JSP中嵌入Java代码中即可
JSP的注释不会显示在客户端
3.4、JSP指令
格式:
<%@page args...%>
<%@include file=""%>
↑↑↑↑直接访问500.jsp会找不到图片,同样是路径问题,这里可以改成${pageContext.request.contextPath}/img/500.png
也可以将img目录修改为resource目录
显式地声明这是一个错误页面
<%@ page isErrorPage="ture"%>
3.5、九大内置对象
- PageContext 保存东西
- Request 保存东西
- Response
- Session 保存东西
- Application 【ServletContext】 保存东西
- config 【ServletConfig】
- out
- page , 几乎不用
- exception 异常
脚本片段中的代码会被原封不动的生成到_jsp.java中,因此,在脚本片段中,注释符号需要使用//【必须保证java语法的正确性】
<%
pageContext.setAttribute("name1","test1");
request.setAttribute("name2","test2");
session.setAttribute("name3","test3");
application.setAttribute("name4","test4");
%>
<%
//从pageContext取出,通过寻找的方式来进行
//从底层到高层(作用域):page-->request-->session-->application
//JVM:双亲委派机制 双亲委派机制是先找上级加载器,再找下级的,最上级没有才会从下级找
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5");
pageContext.setAttribute();
%>
<%--EL表达式取的是setAttribute()中的name1,没有findAttribute()也可以获取--%>
<%--转换成String的name是灰色的说明就没用上,只有<%=name>才用上--%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name5}</h3>
<%=name5%>
<%
pageContext.setAttribute("hello","hello1",pageContext.SESSION_SCOPE);
//上述代码与session.setAttribute("hello","hello1");等价
%>
<%
pageContext.forward("/index.jsp");
//以上代码与request.getRequestDispatcher("/index.php").forward(request,response); 等价
%>
如果EL表达式不生效,请在JSP页面最上面加上:<%@page isELIgnored="false" %>
双亲委派机制,遇到相同类名即向上加载,寻找优先级最高的包。即如果下层有与上层相同的包,则会使用最上层的包(优先级最高)
${}中取的是 上面存的 不是 String的 String那个是无效的
request:客户端向服务器发送请求,产生的数据,用户用完就没用了,比如新闻
session:客户端向服务器发送请求,产生的数据,用户用完一会了还有用,比如购物车
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如聊天数据、统计网站在线人数
3.6、JSP标签、JSTL标签、EL表达式
使用JSTL标签需要导入jar包:
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
JSP标签
EL表达式: ${}
- 获取数据
- 执行运算
- 获取web开发的常用对象
JSTL表达式
JSTL标签库的使用就是为了弥补HTML标签的不足,它自定义许多标签,可以供我们使用,标签的功能和Java代码一样
核心标签 (掌握部分即可)
JSTL标签库使用步骤:
- 引入对应的taglib
- 使用其中的方法
- 在Tomcat中也需要引入JSTL的包,否则会报错:JSTL解析错误
<body>
<%--定义一个变量score,值为85--%>
<c:set var="score" value="85"/>
<c:choose>
<c:when test="${score}>=90">
good
</c:when>
<c:when test="${score}>=80">
just soso
</c:when>
<c:when test="${score}<60">
bad!
</c:when>
</c:choose>
</body>
格式化标签
SQL标签
XML标签
4、JavaBean
实体类
JavaBean有特定的写法
- 必须要有一个无参构造
- 属性必须私有化
- 必须有对应的get/set方法
一般用来和数据库的字段做映射 ORM
ORM:对象关系映射
- 表--->类
- 字段--->属性
- 行记录--->对象
people表
id | name | age | address |
---|---|---|---|
1 | admin1 | 3 | 湖南 |
2 | admin2 | 18 | 湖南 |
3 | admin3 | 24 | 湖南 |
class People{
private int id;
private String name;
private int age;
private String address;
}
class A{
new People(1,"admin1",3,"湖南");
new People(2,"admin2",18,"湖南");
new People(3,"admin3",24,"湖南");
}
新建数据库、库中的表
ajax请求
5、MVC三层架构
Servlet和JSP都可以写Java代码,为了易于维护和使用,Servlet专注于处理i请求以及控制视图跳转【通过重定向或者转发】
JSP专注于显示数据
JAVA类要和数据库连接,需要通过JDBC
之前使用的:
用户直接访问控制层,控制层就可以直接操作数据库:
servlet-->CRUD(曾删改查)-->数据库
弊端:程序十分臃肿,不利于维护
Servlet的代码中,处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码
架构:可以加一层来解决
MVC:Model 模型、View 视图、Controller 控制器
Model:实体类和数据库中对应的一个个字段
- 业务处理:业务逻辑:Service
- 数据持久层:CRUD(增删改查) Dao层
View:JSP页面
-
展示数据
-
提供一些可以供我们操作的请求
-
提供连接发起Servlet请求
Controller:控制器,即我们写的Servlet
- 接收用户的请求
- 响应给客户端内容
- 重定向或者转发
登录--->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username,password)--->交给业务层处理登录业务(判断用户名密码是否正确)--->Dao层查询用户名和密码是否正确--->在数据库中进行查询
MVC三层架构
Dao层去操作数据库,实体类就是单独的了
实体类因为所有人都会用到(公共模块)
6、Filter
Filter:过滤器。用来过滤网站的数据
- 处理中文乱码
- 登录验证
过滤器需要实现过滤器接口
Filter开发步骤
-
导包
-
编写过滤器
-
导包的时候注意:需要导javax.servlet的Filter。否则没用
-
实现Filter接口,重写对应的方法
package com.luo.filter; import javax.servlet.*; import java.io.IOException; public class CharEncodingFilter implements Filter { @Override //初始化 web服务器一启动就初始化了 public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { /* * 1,过滤中的所有代码,在过滤特定请求的时候都会执行 * 2. 必须要让过滤器继续通行:filterChain.doFilter(servletRequest,servletResponse); 【固定代码。不写的话,过滤器不会继续通行】 */ servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println("filter之前:"); filterChain.doFilter(servletRequest,servletResponse); //让我们的请求继续走,如果不写,程序执行到这里就会被拦截而不能继续往下执行。 System.out.println("filter之后:"); } //销毁 @Override public void destroy() { } }
- 在web.xml中配置Filter过滤器
<filter> <filter-name>charEncoding</filter-name> <filter-class>com.luo.filter.CharEncodingFilter</filter-class> </filter> <!--/servlet下的所有请求都会经过该过滤器--> <filter-mapping> <filter-name>charEncoding</filter-name> <url-pattern>/servlet/*</url-pattern> </filter-mapping>
-
7、监听器
实现一个监听器的接口;(有N种)
-
编写一个监听器
实现监听器的接口,重写里面的方法
package com.luo.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; //统计网站在线人数 //创建Session监听 //一旦创建Session就会触发一次这个事件 //HTTPSessionEvent 代表session时间对应的对象 public class OnlineCountListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { ServletContext ctx = httpSessionEvent.getSession().getServletContext(); Integer OnlineCount = (Integer) ctx.getAttribute("OnlineCount"); if(OnlineCount == null){ OnlineCount = new Integer(1); } else { int count = OnlineCount.intValue(); OnlineCount = new Integer(count+1); } ctx.setAttribute("OnlineCount",OnlineCount); } @Override //销毁sessio监听 //一旦销毁session就会触发这个事件 public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { ServletContext ctx = httpSessionEvent.getSession().getServletContext(); Integer OnlineCount = (Integer) ctx.getAttribute("OnlineCount"); if(OnlineCount == null){ OnlineCount = new Integer(0); } else { int count = OnlineCount.intValue(); OnlineCount = new Integer(count-1); } ctx.setAttribute("OnlineCount",OnlineCount); } }
-
web.xml中注册监听器
<listener> <listener-class>com.luo.listener.OnlineCountListener</listener-class> </listener>
-
注册完成之后,index.jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> request.getSession().getAttribute("OnlineCount") <body> <h1>当前有 <span><%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%></span> 人在线</h1> </body> </html>
首次打开页面,显示在线人不不为1的原因:tomcat在部署项目的时候,会启动该项目,生成少量session,因此不为一
需要重启tomcat时选择Redeploy,首次访问时才为1
HTTPSessionEvent 代表session时间对应的对象
Session的销毁:
- 手动:
getSession().invalidate();
- 自动:在web.xml中配置session-config 下的session-timeout
8、过滤器、监听器的常见使用
监听器:GUI编程中经常使用
package com.luo.listener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class GuiListener {
public static void main(String[] args) {
Frame frame = new Frame("中秋节快乐");
Panel panel = new Panel();
frame.setLayout(null);
frame.setBounds(300,300,500,500); //设置frame的大小
frame.setBackground(new Color(0,255,0)); //设置frame的背景颜色
panel.setBounds(50,50,300,300); //设置panel的大小
panel.setBackground(new Color(0,0,255)); //设置panel的背景颜色
frame.add(panel); //将panel(小框)加入到frame中
frame.setVisible(true); //设置frame为可见的
//监听事件,监听关闭事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("关闭中...");
System.exit(0);
}
});
}
}
exit(0) 和 exit(1) 的区别:一个是正常终止,一个是非正常终止
场景二:
用户登录后才能进入主页,用户注销后就不能进入
【使用过滤器可以实现】
如果转发的话,转发到/sys/success.jsp页面不能拿到数据,但是放到session中可以拿到数据
JDBC
什么是JDBC:Java连接数据库
需要jar包的支持
- Java.sql
- javax.sql
- mysql-connector-java... 连接驱动,必须要导入
实验环境搭建
数据库 表的创建
CREATE TABLE users(
id INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(1,'张三','123456','zs@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,'李四','123456','ls@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,'王五','123456','ww@qq.com','2000-01-01');
SELECT * FROM users;
1、导入数据库依赖
<!--mysql的驱动-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
2、IDEA连接数据库
3、固定步骤
- 加载驱动
- 连接数据库,代表数据库
- 向数据库发送SQL的对象Statement,PrepareStatement:CRUD
- 编写SQL
- 执行查询SQL,返回一个ResultSet:结果集
- 关闭连接,释放资源 【先开后关】
增删改查:增删改都是使用executeUpdate
查询使用executeQuery
jdbc?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSl=true
最新的要在后面加上时区:serverTimezone=UTC
驱动是通过反射得到的 IDEA认为可能会找不到 所以要抛出异常
使用预编译
package com.luo.test;
import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class TestJDBC2 {
public static void main(String[] args) throws Exception{
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, username, password);
String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,4);
preparedStatement.setString(2,"admin罗");
preparedStatement.setString(3,"123456");
preparedStatement.setString(4,"1297725225@qq.com");
preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("insert success!");
}
preparedStatement.close();
connection.close();
}
}
事务
要么都成功,要么都失败
ACID原则:保证数据的安全
开启事务
事务提交 commit()
事务回滚 roolback()
关闭事务
转账:
a:1000
b:1000
转账过程要么都成功,要么都失败
Junit(单元测试):写一个方法可以随时测试,不需要new或者main方法。
依赖:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
简单使用
@Test注解只有在方法上有效,只要加了这个注解的方法就可以直接运行
随便写一个东西就可以测试
package com.luo.test;
import org.junit.jupiter.api.Test;
public class TestJDBC3 {
@Test
public void test(){
System.out.println("hello");
}
}
失败的时候是红色,报错
smbms服务搭建
搭建一个环境
事务关闭自动提交默认开启事务
在java代码中:
通知数据库开启事务(flase为开启):
connection.setAutoCommit(false);
准备工作
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql//localhost:3306?useUnicode=true&characterEncoding=utf-8
username=root
password=123456
编写DAO层:
package com.luo.dao;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class BaseDao {
private static String driver;
private static String url;
private static String username;
private static String password;
static {
//Properties类用来读取配置文件
Properties properties = new Properties();
InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}
//获取数据库的连接
public static Connection getConnection(){
//通过反射常见 Driver 对象.
Connection connection = null;
try {
Class.forName(driver);
connection = DriverManager.getConnection(url,username,password);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
//编写查询公共类的方法
public static ResultSet execute(Connection connection, String sql, Object[] params, ResultSet resultSet, PreparedStatement preparedStatement) throws SQLException {
//预编译sql,在后面直接执行就可以了
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
//setObject,占位符从1开始,但是数组是从0开始
preparedStatement.setObject(i+1,params[i]);
}
return resultSet;
}
//编写增删改公共方法
public static int execute(Connection connection,String sql,Object[] params,PreparedStatement preparedStatement) throws SQLException {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
//setObject,占位符从1开始,但是数组是从0开始
preparedStatement.setObject(i+1,params[i]);
}
int updateRows = preparedStatement.executeUpdate();
return updateRows;
}
public static boolean closeResource(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet){
boolean flag = true;
if(resultSet!=null){
try {
resultSet.close();
//GC回收
resultSet = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
//GC回收
preparedStatement = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
if(connection!=null){
try {
connection.close();
//GC回收
connection = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
return flag;
}
}
编写过滤器;
package com.luo.filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
public void destroy() {
}
}
登录功能的实现
1.编写前端
2.设置首页
Dao层:持久化层
面向接口编程
3.编写dao层登录用户的接口
package com.luo.dao.user;
import com.luo.pojo.User;
import java.sql.Connection;
import java.sql.SQLException;
public interface UserDao {
//得到要登录的用户
public User getLoginUser(Connection connection,String userCode) throws SQLException;
}
4.编写dao接口的实现类
package com.luo.dao.user;
import com.luo.dao.BaseDao;
import com.luo.pojo.User;
import com.mysql.jdbc.PreparedStatement;
import java.sql.Connection;
//import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 处理逻辑:
* 从数据库中得到要登录的用户
*/
public class UserDaoImpl implements UserDao{
public User getLoginUser(Connection connection, String userCode) throws SQLException {
// ? 是为了保证安全,使用预编译sql
PreparedStatement pstm = null;
ResultSet rs = null;
User user = null;
if(connection!=null){
String sql = "select * from smbms_user where userCode= ? ";
Object[] params = {userCode};
rs = BaseDao.execute(connection,pstm,rs,sql,params);
//rs = BaseDao.execute(connection,pstm,rs,sql,params);
//rs = BaseDao.execute(connection,pstm,rs,sql,params);
if(rs.next()){
user = new User();
user.setId(rs.getInt("id"));
user.setUserCode(rs.getString("userCode"));
user.setUserName(rs.getString("userName"));
user.setUserPassword(rs.getString("userPassword"));
user.setGender(rs.getInt("gender"));
user.setBirthday(rs.getDate("birthday"));
user.setPhone(rs.getString("phone"));
user.setAddress(rs.getString("address"));
user.setUserRole(rs.getInt("userRole"));
user.setCreateBy(rs.getInt("createdBy"));
user.setCreationDate(rs.getTimestamp("creationDate"));
user.setModifyBy(rs.getInt("modifyBy"));
user.setModifyDate(rs.getTimestamp("modifyDate"));
}
BaseDao.closeResource(null,pstm,rs);
}
return user;
}
}
5.业务层接口
UserService.java:
package com.luo.service.user;
import com.luo.pojo.User;
public interface UserService {
//用户登录
public User login(String usercode,String password);
}
6.业务层实现类
UserServiceImpl.java
package com.luo.service.user;
import com.luo.dao.BaseDao;
import com.luo.dao.user.UserDao;
import com.luo.dao.user.UserDaoImpl;
import com.luo.pojo.User;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.SQLException;
public class UserServiceImpl implements UserService {
//业务层都会调用dao层,所以需要引入Dao层
private UserDao userDao;
public UserServiceImpl(){
//构造函数,当实现UserServiceImpl的时候即自动实例化
userDao = new UserDaoImpl();
}
public User login(String userCode, String password) {
Connection connection = null;
User user = null;
try {
connection = BaseDao.getConnection();
//通过业务层调用具体的数据库操作
user = userDao.getLoginUser(connection,userCode);
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(connection,null,null);
}
return user;
}
@Test
public void test(){
UserServiceImpl userService = new UserServiceImpl();
User admin = userService.login("admin","1234567");
System.out.println(admin.getUserPassword());
}
}
7.编写servlet
package com.luo.servlet.user;
import com.luo.pojo.User;
import com.luo.service.user.UserService;
import com.luo.service.user.UserServiceImpl;
import com.luo.servlet.util.Constants;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("LoginServlet--start...");
String userCode = req.getParameter("userCode");
String userPassword = req.getParameter("userPassword");
//和数据库中的密码进行对比,调用业务层
UserService userService = new UserServiceImpl();
User user = userService.login(userCode,userPassword); //这里已经把登录的人查出来了
if(user!= null){
//将用户的信息放入session中
req.getSession().setAttribute(Constants.USER_SESSION,user);
//跳转到内部主页
resp.sendRedirect("/jsp/frame.jsp");
}
else {//查不到该用户,无法登录
//转发回登录页面,并提示用户名或者密码错误
req.setAttribute("error","用户名或密码错误");
req.getRequestDispatcher("login.jsp").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
8.注册Servlet
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.luo.servlet.user.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
9.测试访问,确保以上功能成功
测试时出现报错:
Establishing SSL connetcion whitout server's identity verification is not recommended.
提示不安全的链接,则在db.properties文件中修改url为:useSSL=true
即:url=jdbc:mysql//localhost:3306?useSSL=true&useUnicode=true&characterEncoding=utf-8
登录功能优化
注销功能:
移除Session,返回登录界面
LogoutServlet:
package com.luo.servlet.user;
import com.luo.servlet.util.Constants;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//移除用户的Constants.USER_SESSION
req.getSession().removeAttribute(Constants.USER_SESSION);
resp.sendRedirect(req.getContextPath()+"/login.jsp");//返回登录页面
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
登录拦截优化
SysFilter:
package com.luo.filter;
import com.luo.pojo.User;
import com.luo.servlet.util.Constants;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SysFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//过滤器,从session中获取用户
User user = (User) request.getSession().getAttribute(Constants.USER_SESSION);
if(user == null){
response.sendRedirect("/smbms/error.jsp");
}
else{
filterChain.doFilter(req,resp);
}
}
public void destroy() {
}
}
chain.dofilter作用是寻找下一个filter,但是user为null就没必要再寻找下一个filter过滤了所以写在false没问题
这里如果使用后退的话还是可以进去那个页面一下的,但是点击任何一个地方就会跳转到错误页面,一开始我还以为是我的过滤器不ok呢
密码修改
focus 聚焦
blur 失去焦点
三层架构,职责分离。需要修改就知道那一块出了问题
servlet层 获取参数,页面重定向
service层专注于处理业务,没有与数据库进行操作
1.导入前端素材
<li><a href="${pageContext.request.contextPath }/jsp/pwdmodify.jsp">密码修改</a></li>
2.写项目,建议从底层向上写
3.UserDao接口
public int updatePwd(Connection connection,int id,int password) throws SQLException;
4.UserDao接口实现类
public int updatePwd(Connection connection, int id, int password) throws SQLException {
PreparedStatement pstm = null;
int execute = 0;
if(connection != null){
String sql = "update smbms_user set userPassword = ? where id = ?";
Object params[] = {password,id};
execute = BaseDao.execute(connection,pstm,sql,params);
BaseDao.closeResource(null,pstm,null);
}
return execute;
}
5.UserService层
//根据用户ID修改密码
public boolean updatePwd(int id,int pwd);
6.UserService实现类
public boolean updatePwd(int id, int pwd) {
Connection connection = null;
boolean flag = false;
try {
connection = BaseDao.getConnection();
if(userDao.updatePwd(connection,id,pwd)>0){
flag = true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(connection,null,null);
}
return flag;
}
7.实现复用。需要提取出方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if (method != null && method.equals("savepwd")){
this.updatePwd(req, resp);
}
}
8.测试
优化密码修改使用Ajax
Ajax 在页面没有刷新的情况下实现了交互
后台代码
public void pwdmodify(HttpServletRequest req,HttpServletResponse resp){
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String oldpassword = req.getParameter("oldpassword");
//万能的Map : 结果集
Map<String, String> resultMap = new HashMap<String, String>();
if(o == null){//Session失效
resultMap.put("result","error");
}
else if(StringUtils.isNullOrEmpty(oldpassword)){
resultMap.put("result","error");
}else{
String userPassword = ((User) o).getUserPassword();
if(oldpassword.equals(userPassword)){
resultMap.put("result","true");
}
else{
resultMap.put("result","false");
}
}
try {
resp.setContentType("application/json");//让上述方法返回一个JSON的值
// resp.setContentType("text/html");
// resp.setContentType("text/javascript");
PrintWriter writer = resp.getWriter();
writer.write(JSONArray.toJSONString(resultMap));
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
用户管理实现
1.导入分页的工具类 (手写)
package com.luo.servlet.util;
public class PageSupport {
//当前页码-来自用户输入
private int currentPageNo = 1;
//总数量 (表)
private int totalCount = 0;
//页面容量
private int pageSize;
//总页数-totalCount/pageSize (+1)
private int totalPageCount;
public int getCurrentPageNo(){
return currentPageNo;
}
public void setCurrentPageNo(int currentPageNo){
if(currentPageNo > 0){
this.currentPageNo = currentPageNo;
}
}
public int getTotalCount(){
return totalCount;
}
public void setTotalCount(int totalCount){
this.totalCount = totalCount;
//设置总页数
this.setTotalPageCountByRs();
}
public int getPageSize(){
return pageSize;
}
public void setPageSize(int pageSize){
if(pageSize > 0){
this.pageSize = pageSize;
}
}
public int getTotalPageCount(){
return totalPageCount;
}
public void setTotalPageCount(int totalPageCount){
this.totalPageCount = totalPageCount;
}
public void setTotalPageCountByRs(){
if(this.totalCount % this.pageSize ==0){
this.totalPageCount = this.totalCount / this.pageSize;
}
else if(this.totalCount % this.pageSize > 0){
this.totalPageCount = this.totalCount / this.pageSize + 1;
}
else {
this.totalPageCount = 0;
}
}
}
2.用户列表页面导入
userlist.jsp
获取用户数量
1.UserDao
public List<User> getUserList(Connection connection,String userName,int userRole,int currentPageNo,int pageSize) throws Exception;
2.UserDaoImpl
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception {
//TODO Auto-generated method stub
PreparedStatement pstm = null;
ResultSet rs = null;
List<User> userList = new ArrayList<User>();
if(connection != null){
StringBuffer sql = new StringBuffer();
sql.append("select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.userRole = r.id");
List<Object> list = new ArrayList<Object>();
if(!StringUtils.isNullOrEmpty(userName)){
sql.append(" and u.userName like ?");
list.add("%"+userName+"%");
}
if(userRole > 0){
sql.append(" and u.userRole = ?");
list.add(userRole);
}
sql.append(" order by creationDate DESC limit ?,?");
currentPageNo = (currentPageNo-1)*pageSize;
list.add(currentPageNo);
list.add(pageSize);
Object[] params = list.toArray();
System.out.println("sql ----->" + sql.toString());
rs = BaseDao.execute(connection,pstm,rs,sql.toString(),params);
while (rs.next()){
User _user = new User();
_user.setId(rs.getInt("id"));
_user.setUserCode(rs.getString("userCode"));
_user.setUserName(rs.getString("userName"));
_user.setGender(rs.getInt("gender"));
_user.setBirthday(rs.getDate("birthday"));
_user.setPhone(rs.getString("phone"));
_user.setUserRole(rs.getInt("userRole"));
_user.setUserRoleName(rs.getString("userRoleName"));
userList.add(_user);
}
BaseDao.closeResource(null,pstm,rs);
}
return userList;
}
}
3.UserService
//根据条件查询用户列表
public List<User> getUserList(String queryUserName,int queryUserRole,int currentPageNo,int pageSize);
4.UserServiceImpl
public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize) {
Connection connection = null;
List<User> userList = null;
System.out.println("queryUserName --->" + queryUserName);
System.out.println("queryUserRole --->" + queryUserRole);
System.out.println("currentPageNo --->" + currentPageNo);
System.out.println("pageSize --->" + pageSize);
try {
userList = userDao.getUserList(connection,queryUserName,queryUserRole,currentPageNo,pageSize);
connection = BaseDao.getConnection();
} catch (Exception e) {
e.printStackTrace();
} finally {
BaseDao.closeResource(connection,null,null);
}
return userList;
}
获取角色操作
为了职责统一,可以把角色的操作单独存放在一个包中。和POJO类对应
RoleDao
public interface RoleDao {
//获取角色列表
public List<Role> getRoleList(Connection connection) throws SQLException;
}
RoleDaoImpl
package com.luo.dao.role;
import com.luo.dao.BaseDao;
import com.luo.pojo.Role;
import com.mysql.jdbc.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class RoleDaoImpl implements RoleDao{
//获取角色列表
public List<Role> getRoleList(Connection connection) throws SQLException {
PreparedStatement pstm = null;
ResultSet resultSet = null;
ArrayList<Role> roleList = new ArrayList<Role>();
if(connection != null){
String sql = "select * from smbms_role";
Object[] params = {};
resultSet = BaseDao.execute(connection,pstm,resultSet,sql,params);
//读取所有角色,放入一个列表中
while(resultSet.next()){
Role _role = new Role();
_role.setId(resultSet.getInt("id"));
_role.setRoleCode(resultSet.getString("roleCode"));
_role.setRoleName(resultSet.getString("roleCode"));
roleList.add(_role);
}
BaseDao.closeResource(null,pstm,resultSet);
}
return roleList;
}
}
RoleService
package com.luo.service.role;
import com.luo.pojo.Role;
import java.util.List;
public interface RoleService {
//获取角色列表
public List<Role> getRoleList();
}
RoleServiceImpl
package com.luo.service.role;
import com.luo.dao.BaseDao;
import com.luo.dao.role.RoleDao;
import com.luo.dao.role.RoleDaoImpl;
import com.luo.pojo.Role;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class RoleServiceImpl implements RoleService{
//引入Dao
private RoleDao roleDao;
public RoleServiceImpl(){
roleDao = new RoleDaoImpl();
}
public List<Role> getRoleList() {
Connection connection = null;
List<Role> roleList = null;
try {
connection = BaseDao.getConnection();
roleList = roleDao.getRoleList(connection);
} catch (SQLException e) {
e.printStackTrace();
}
finally {
BaseDao.closeResource(connection,null,null);
}
return roleList;
}
}
4、用户显示的Servlet
1.获取用户前端的数据
2.判断请求是否需要执行,看参数的值判断
3.为了实现分页,需要计算出当前页面和总页面,页面大小
4.用户列表展示
5.返回前端
文件上传
调优:
- 为了保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如WEB-INF目录下。
- 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名 【uuid 随机生成数、md5 、 位运算算法】
- 要限制文件上传的最大值
- 可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法
WEB-INF目录无法直接访问,只能通过重定向来进行间接访问
Java虚拟机底层是用C++写的
Java不能操作本地方法,因为Java的一些都是操作在JVM上
JNI = Java Native Interface
Java无法操作计算机 , 因为有一层
不同的操作系统都有一个统一的JVM
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现