笔记备忘
参考课程:B站狂神说JavaWeb
https://www.bilibili.com/video/BV12J411M7Sj
web开发:
web:网页
静态web
动态web
在java中,动态web资源开发中的技术统称为JavaWeb;
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
Servlet是由Web服务器调用,web服务器收到浏览器的请求之后,会:
一个servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
一个servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello1url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello2url-pattern>
servlet-mapping>
一个servlet可以指定通用映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello/*url-pattern>
servlet-mapping>
*----->在正则表达式中表示通配符
指定一些后缀或前缀
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
这里的.do是后缀,后缀可以设置成任意值,但是*前不能加反斜杠
默认请求路径(不建议使用)
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
优先级问题
指定了固有的路径优先级最高,如果找不到会走默认的处理请求。
web容器启动时,它会为每个web程序创建一个ServletContext对象,它代表了当前的web应用;
应用:
在此servlet中存放的数据,可以在另一个servlet中得到
getInitParam
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String jdbcurl = context.getInitParameter("jdbcurl");
resp.getWriter().print(jdbcurl);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
context.getRequestDispatcher("/getp").forward(req,resp);
}
Properties
发现:都被打包到同一个路径下:classes,我们称此路径为类路径
思路:需要一个文件流
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//读取资源文件
InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.properties");
Properties prop = new Properties();
prop.load(is);
String username = prop.getProperty("username");
String password = prop.getProperty("password");
resp.getWriter().println(username);
resp.getWriter().println(password);
}
web服务器收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletResponse。
java下载文件
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 获取下载文件的路径
//String realPath = this.getServletContext().getRealPath("/1.png");
String realPath = "D:\\Project\\Java-learn-all\\Response\\src\\main\\resources\\1.png";
//resp.getWriter().print("下载的文件名为:"+realPath);
System.out.println("下载的文件名为:"+realPath);
// 2. 下载的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
// 3. 设置想办法让浏览器能够支持下载我们需要的东西--下载中文文件名文件时,使用URLEncoder,否则中文文件名可能无法显示
resp.setHeader("Content-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. 将ServletOutputStream流写入buffer缓冲区
while((len=in.read(buffer)) > 0)
{
out.write(buffer,0,len);
}
out.close();
in.close();
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//验证码功能
//浏览器每三秒刷新一次
resp.setHeader("refresh","0.5");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
//设置背景颜色
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(Color.white);
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());
}
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;
}
重定向定义:一个web资源收到客户端请求之后,会通知客户端去访问另一个web资源,这个过程叫做重定向。
void sendRedirect(String var1) throws IOException;
resp.sendRedirect("/此处写路径")
常见场景
面试题:请聊聊重定向和转发的区别?
相同点
不同点
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http中请求的信息会被封装到HttpServletRequest中,通过此HttpServletRequest方法,可以获得客户端的所有信息。
getParameter
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println("----------------------------------------");
System.out.println(Arrays.toString(hobbies));
System.out.println(username+" : "+password);
System.out.println("----------------------------------------");
//这里的 / 代表当前web应用---不用加项目路径的/r
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
会话:用户打开一个浏览器,访问多个web资源,关闭浏览器的过程称为会话。
有状态会话:
网站如何证明有人访问过
客户端 服务端
cookie
session
网站登陆过后,下次再访问自动登录。
1.从请求中得到cookie信息
2.服务器响应客户端的cookie
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setHeader("content-type","text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
//从请求中获取cookie
Cookie[] cookies = req.getCookies();
if(cookies != null)
{
out.print("上一次访问的时间为:");
for(int i = 0;i < cookies.length;i++)
{
if(cookies[i].getName().equals("lastlogintime"))
{
long time = Long.parseLong(cookies[i].getValue());
Date date = new Date(time);
out.write(date.toGMTString());
}
}
}
else{
out.print("this is the first time you access this web");
}
//服务器给客户端响应一个cookie
Cookie cookie = new Cookie("lastlogintime",System.currentTimeMillis()+"");
//设置cookie的有效期
cookie.setMaxAge(48*60*60);
resp.addCookie(cookie);
}
cookie:一般存在本地用户目录下的Appdata中
一个网站的Cookie是否存在上限
删除cookie
编码解码
URLEncoder.encode(string,"utf-8")
URLDecoder.decode( ,"utf-8")
Session:服务器会给每一个用户(浏览器)创建一个Session对象。可以保存信息。一个浏览器对应一个Session,只要不关闭浏览器。
Session和Cookie的区别
使用场景:
过期时间:可以在web.xml中设置,
JSP:Java Server Pages
JSP与HTML的区别:
执行的过程是什么
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
JSP最终也会被转化为一个JAVA类
JSP本质上就是一个Servlet
支持java所有语法,即可以嵌入java代码。
jsp脚本片段:<% java代码 %>
jsp表达式: <%=变量或者等式%>
jsp声明: <%! %>—会被编译到jsp对应的java文件的类中,其他的就会生成到jspService的方法中。
JSP的注释在客户端不显示,HTML注释会显示。
<%@page args.... %>
<%@include file="" %> ---->公有信息可以这么导入,比如网页的头部和脚部,相当于吧代码导入
JSP标签
本质是拼接页面,所以其他文件中的变量与本文件有重名也可以
依赖
<dependency>
<groupId>javax.servlet.jsp.jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
EL表达式:${ }
<jsp:forward page="/jsptag2.jsp">
<jsp:param name="name" value="小名"/>
<jsp:param name="age" value="19"/>
jsp:forward>
参考:https://www.runoob.com/jsp/jsp-jstl.html
在tomcat中也需要引入jstl的包
实体类
JavaBean有特定的写法:
一般用来和数据库的字段做映射ORM
ORM:对象关系映射
MVC:Model view Controller 模型、视图、控制器
用户直接访问控制层,控制层可以直接操作数据库
弊端:程序臃肿,不利于维护
Model
View
Controller
Filter:过滤器,过滤网站数据
1、导包
2、编写过滤器
public class CharacterEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter启动");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(request,response);
}
@Override
public void destroy() {
System.out.println("CharacterEncodingFilter销毁");
}
}
在web.xml中配置
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.future.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/servlet/*
实现监听器
public class OnlineCountLisener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext ctx = se.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
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext ctx = se.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);
}
}
jar包支持
maven中导入jar包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
mysql连接,参考https://www.runoob.com/java/java-mysql-connect.html
mysql8.0版本和5.X版本有些许不同
步骤
String url = "jdbc:mysql://localhost:3306/database?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
String username = "root";
String password = "*******";
//1、加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3、向数据库发送sql对象
Statement statement = connection.createStatement();
//4、编写sql语句
String sql = "select * from student";
//5、执行查询sql
ResultSet rs = statement.executeQuery(sql);
while(rs.next())
{
System.out.println("rank = "+rs.getObject("rank"));
System.out.println("class = "+rs.getObject("class"));
System.out.println("name = "+rs.getObject("name"));
System.out.println("score = "+rs.getObject("score"));
}
//6、关闭资源,先开后关
rs.close();
statement.close();
connection.close();
要么都成功,要么都失败
ACID原则:保证数据的安全
开启事物
事物提交 commit()
事物回滚 rollback()
关闭事物
//开启事物
connection.setAutoCommit(false);
简单使用
@Test注解只有在方法上有效,只要加了这个注解就可以直接运行。
————----————JavaWeb完结——————————
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//判断上传的是普通表单还是带文件的表单
if (!ServletFileUpload.isMultipartContent(req)){
return;//普通表单直接结束
}
//创建上传文件的保存路径,放在WEB-INF目录下,用户不可以直接访问,较为安全
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
//如果目录不存在,需要创建一个文件夹
if(!uploadFile.exists()){
uploadFile.mkdir();
}
//缓存,临时文件,假设文件超过预期大小,则先放入缓存,过几天自动删除或者提示用户自动转为永久
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File tmpFile = new File(tmpPath);
//如果目录不存在,需要创建一个文件夹
if(!tmpFile.exists()){
tmpFile.mkdir();
}
//处理上传的文件,一般用流来获取,但是比较麻烦,这里使用Apache的文件上传组件来实现,common-fileupload
try {
//1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制
DiskFileItemFactory factory = getDiskFileItemFactory(tmpFile);
//2.获取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
//3.处理上传文件
String msg = uploadParseRequest(upload,req,uploadPath);
//servlet请求转发消息
req.setAttribute("msg",msg);
req.getRequestDispatcher("info.jsp").forward(req,resp);
} catch (FileUploadException e) {
e.printStackTrace();
}
}
public static DiskFileItemFactory getDiskFileItemFactory(File file){
DiskFileItemFactory factory = new DiskFileItemFactory();
//通过这个工厂设置一个缓冲区,当上传文件大于这个缓冲区的时候,将它放入临时文件
factory.setSizeThreshold(1024*1024);//设置缓冲区的大小为1M;
factory.setRepository(file);
return factory;
}
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
ServletFileUpload upload = new ServletFileUpload(factory);
//监听上传的进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long l, long l1, int i) {
System.out.println("总大小:"+l1+" 已上传:"+l);
}
});
//处理乱码
upload.setHeaderEncoding("UTF-8");
//设置单个文件的最大值
upload.setFileSizeMax(1024*1024*10);
//设置总共能够上传文件的大小
upload.setSizeMax(1024*1024*100);
return upload;
}
public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest req,String uploadPath) throws FileUploadException,IOException{
String msg = "";
//3.处理上传文件
//前端请求解析。封装成一个FileItem对象,需要从ServletFileUpload获取
try {
List<FileItem> fileItems = upload.parseRequest(req);
for(FileItem fileItem : fileItems){
//判断上传的文件是普通的表单还是带文件的表单
if(fileItem.isFormField()){
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8");
System.out.println(name +":" + value);
}else{ //文件
//======处理文件
String uploadFileName = fileItem.getName();
System.out.println("上传的文件名:"+uploadFileName);
if(uploadFileName.trim().equals("")||uploadFileName == null){
continue;
}
//获得上传文件名
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/")+1);
//获取后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1);
System.out.println("文件信息[件名: " + fileName + " ---文件类型" + fileExtName + "]");
//使用UUID(唯一识别通用码)保证文件名的唯一
String uuidPath = UUID.randomUUID().toString();
//======存放地址
//文件真实存在的路径
String realPath = uploadPath+"/"+uuidPath;
//给每个文件创建一个对应的文件夹
File realPathFile = new File(realPath);
if(!realPathFile.exists()){
realPathFile.mkdir();
}
//======文件传输
//获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
FileOutputStream fos = new FileOutputStream(realPath + "/"+fileName);
//创建一个缓冲区
byte[] buffer = new byte[1024*1024];
//判断是否读取完毕
int len = 0;
while((len = inputStream.read(buffer)) > 0){
fos.write(buffer,0,len);
}
//关闭流
fos.close();
inputStream.close();
//上传成功,清除临时文件
msg = "文件上传成功";
fileItem.delete();
}
}
} catch (Exception e) {
msg = "文件上传失败";
e.printStackTrace();
}
return msg;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
利用maven创建的项目,保存的文件在Tomcat目录下的webapps中。普通的web项目,保存的文件在target目录下/out目录下。
纯文本邮件发送
mport com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.*;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
public class SendMail {
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
prop.setProperty("mail.host","smtp.qq.com");//设置QQ邮件服务器
prop.setProperty("mail.transport.protocol","smtp");//邮件发送协议
prop.setProperty("mail.smtp.auth","true");//需要验证用户名密码
//QQ邮箱,还要设置SSL加密,加上以下代码
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable","true");
prop.put("mail.smtp.ssl.socketFactory",sf);
//使用Java发送邮件的5个步骤
//1.创建定义整个应用程序所需的环境信息的Session对象
//QQ才有!其他邮箱就不用
Session session=Session.getDefaultInstance(prop, new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
//发件人邮件用户名、授权码
return new PasswordAuthentication("[email protected]","qpszlppmatiweiaa");
}
});
//开启session的debug模式,这样可以查看到程序发送Email的运行状态
session.setDebug(true);
//2.通过session得到transport对象
Transport ts=session.getTransport();
//3.使用邮箱的用户名和授权码连上邮件服务器
ts.connect("smtp.qq.com","[email protected]","qpszlppmatiweiaa");
//4.创建邮件:写文件
//注意需要传递session
MimeMessage message=new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress("[email protected]"));
//指明邮件的收件人
message.setRecipient(Message.RecipientType.TO,new InternetAddress("[email protected]"));
//邮件标题
message.setSubject("发送的标题");
//邮件的文本内容
message.setContent("内容","text/html;charset=UTF-8");
//5.发送邮件
ts.sendMessage(message,message.getAllRecipients());
//6.关闭连接
ts.close();
}
}
带有附件的邮件发送
public class SendMail3 {
public static void main(String[] args) throws Exception {
//包含文件的发送
//创建一个配置文件保存并读取信息
Properties properties = new Properties();
//设置qq邮件服务器
properties.setProperty("mail.host","smtp.qq.com");
//设置发送的协议
properties.setProperty("mail.transport.protocol","smtp");
//设置用户是否需要验证
properties.setProperty("mail.smtp.auth", "true");
//=================================只有QQ存在的一个特性,需要建立一个安全的链接
// 关于QQ邮箱,还要设置SSL加密,加上以下代码即可
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", sf);
//=================================准备工作完毕
//1.创建一个session会话对象;
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("[email protected]","qpszlppmatiweiaa");
}
});
//可以通过session开启Dubug模式,查看所有的过程
session.setDebug(true);
//2.获取连接对象,通过session对象获得Transport,需要捕获或者抛出异常;
Transport tp = session.getTransport();
//3.连接服务器,需要抛出异常;
tp.connect("smtp.qq.com","[email protected]","qpszlppmatiweiaa");
//4.连接上之后我们需要发送邮件;
MimeMessage mimeMessage = imageMail(session);
//5.发送邮件
tp.sendMessage(mimeMessage,mimeMessage.getAllRecipients());
//6.关闭连接
tp.close();
}
public static MimeMessage imageMail(Session session) throws MessagingException {
//消息的固定信息
MimeMessage mimeMessage = new MimeMessage(session);
//邮件发送人
mimeMessage.setFrom(new InternetAddress("[email protected]"));
//邮件接收人,可以同时发送给很多人,我们这里只发给自己;
mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
mimeMessage.setSubject("我也不知道是个什么东西就发给你了"); //邮件主题
/*
编写邮件内容
1.图片
2.附件
3.文本
*/
//图片
MimeBodyPart body1 = new MimeBodyPart();
body1.setDataHandler(new DataHandler(new FileDataSource("src/resources/1.png")));
body1.setContentID("yhbxb.png"); //图片设置ID
//文本
MimeBodyPart body2 = new MimeBodyPart();
body2.setContent("请注意,我不是广告","text/html;charset=utf-8");
//附件
MimeBodyPart body3 = new MimeBodyPart();
body3.setDataHandler(new DataHandler(new FileDataSource("src/resources/log4j.properties")));
body3.setFileName("log4j.properties"); //附件设置名字
MimeBodyPart body4 = new MimeBodyPart();
body4.setDataHandler(new DataHandler(new FileDataSource("src/resources/1.txt")));
body4.setFileName(""); //附件设置名字
//拼装邮件正文内容
MimeMultipart multipart1 = new MimeMultipart();
multipart1.addBodyPart(body1);
multipart1.addBodyPart(body2);
multipart1.setSubType("related"); //1.文本和图片内嵌成功!
//new MimeBodyPart().setContent(multipart1); //将拼装好的正文内容设置为主体
MimeBodyPart contentText = new MimeBodyPart();
contentText.setContent(multipart1);
//拼接附件
MimeMultipart allFile =new MimeMultipart();
allFile.addBodyPart(body3); //附件
allFile.addBodyPart(body4); //附件
allFile.addBodyPart(contentText);//正文
allFile.setSubType("mixed"); //正文和附件都存在邮件中,所有类型设置为mixed;
//放到Message消息中
mimeMessage.setContent(allFile);
mimeMessage.saveChanges();//保存修改
return mimeMessage;
}
}
JavaWeb实现邮件发送:https://blog.csdn.net/qq_54897873/article/details/118557180
使用多线程,防止出现耗时,和网站注册人数过多的情况;
maven的常见问题,资源导出失败
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>