JavaWeb
笔记备忘 参考课程:B站狂神说JavaWeb https://www.bilibili.com/video/BV12J411M7Sj
1、Web基本概念
web开发:
-
web:网页 -
静态web
-
动态web
- 淘宝等几乎所有网站
- 内容会根据不同的人发生变化
- 技术栈:Servlet/JSP,ASP,PHP
在java中,动态web资源开发中的技术统称为JavaWeb;
2、Servlet
2.1、Servlet简介
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
2.2、Servlet原理
Servlet是由Web服务器调用,web服务器收到浏览器的请求之后,会:
2.3、Mapping问题
-
一个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可以指定通用映射路径 <servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
*----->在正则表达式中表示通配符 -
指定一些后缀或前缀 <servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
这里的.do是后缀,后缀可以设置成任意值,但是*前不能加反斜杠 -
默认请求路径(不建议使用) <servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
-
优先级问题 指定了固有的路径优先级最高,如果找不到会走默认的处理请求。
2.4、ServletContext
web容器启动时,它会为每个web程序创建一个ServletContext对象,它代表了当前的web应用;
应用:
1、共享数据
在此servlet中存放的数据,可以在另一个servlet中得到
2、获取初始化参数
getInitParam
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String jdbcurl = context.getInitParameter("jdbcurl");
resp.getWriter().print(jdbcurl);
}
3、请求转发
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
context.getRequestDispatcher("/getp").forward(req,resp);
}
4、读取资源文件
Properties
- 在java目录下新建properties
- 在resources目录下新建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);
}
2.5、HttpServletResponse
web服务器收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletResponse。
- 如果要获取客户端请求过来的参数:找HttpServletRequest
- 如果要客户端的一些信息,找HttpServletResponse
常见应用
1、向浏览器输出消息
2、下载文件
- 获取下载文件的路径
- 下载的文件名
- 设置想办法让浏览器能够支持下载我们需要的东西
- 获取下载文件的输入流
- 创建缓冲区
- 获取OutputStream对象
- 将FileOutputStream流写入buffer缓冲区
- 使用OutputStream将缓冲区的数据输出到客户端
java下载文件
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String realPath = "D:\\Project\\Java-learn-all\\Response\\src\\main\\resources\\1.png";
System.out.println("下载的文件名为:"+realPath);
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
resp.setHeader("Content-disposition","attachment;filename"+URLEncoder.encode(fileName,"UTF-8"));
FileInputStream in = new FileInputStream(realPath);
int len = 0;
byte[] buffer = new byte[1024];
ServletOutputStream out = resp.getOutputStream();
while((len=in.read(buffer)) > 0)
{
out.write(buffer,0,len);
}
out.close();
in.close();
}
3、验证码功能
- 前端实现
- 后端实现:需要用到java的图片类来生成图片
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;
}
4、实现重定向
重定向定义:一个web资源收到客户端请求之后,会通知客户端去访问另一个web资源,这个过程叫做重定向。
void sendRedirect(String var1) throws IOException;
resp.sendRedirect("/此处写路径")
常见场景
面试题:请聊聊重定向和转发的区别?
相同点
不同点
- 请求转发时,url不会产生变化 307
- 重定向时候,url地址栏会发生变化 302
2.6、HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http中请求的信息会被封装到HttpServletRequest中,通过此HttpServletRequest方法,可以获得客户端的所有信息。
1、获取前端参数
getParameter
2、请求转发–注意与ServletContext的请求转发的区别
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("----------------------------------------");
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
3、Cookie和Session
3.1、会话
会话:用户打开一个浏览器,访问多个web资源,关闭浏览器的过程称为会话。
有状态会话:
网站如何证明有人访问过
客户端 服务端
- 服务器给客户端一个证明,客户端下次访问时只要带上证明即可;cookie
- 服务器已登记,下次同一用户再次访问时,直接匹配。
3.2、保存会话的两种技术
cookie
session
- 服务器技术,利用此技术,保存会话信息,把信息和数据放在Session中。
网站登陆过后,下次再访问自动登录。
3.3、Cookie
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[] 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 = new Cookie("lastlogintime",System.currentTimeMillis()+"");
cookie.setMaxAge(48*60*60);
resp.addCookie(cookie);
}
cookie:一般存在本地用户目录下的Appdata中
一个网站的Cookie是否存在上限
- 一个cookie只能存放一个信息
- 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie
- cookie大小有限制4kb
- 300个cookie浏览器上限
删除cookie
- 不设置有效期,关闭浏览器,自动失效;
- 设置有效时间为0;
编码解码
URLEncoder.encode(string,"utf-8")
URLDecoder.decode( ,"utf-8")
3.4、Session(重点)
Session:服务器会给每一个用户(浏览器)创建一个Session对象。可以保存信息。一个浏览器对应一个Session,只要不关闭浏览器。
Session和Cookie的区别
- Cookie可以把用户的数据写给浏览器,让用户的浏览器保存(可以保存多个)
- Session把用户的数据写到独占Session中,服务器端保存(保存重要的信息,减小服务器的资源的浪费)
- Session对象由服务器创建。
使用场景:
- 保存一个登录的信息
- 购物车信息
- 在整个网站中经常会使用的数据,保存在Session中。
过期时间:可以在web.xml中设置,
4、JSP
4.1 含义
JSP:Java Server Pages
JSP与HTML的区别:
- HTML只给用户提供静态数据
- JSP中可以嵌入JAVA代码,为用户提供动态数据
4.2 JSP原理
执行的过程是什么
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
JSP最终也会被转化为一个JAVA类
JSP本质上就是一个Servlet
4.3 JSP的基本语法
支持java所有语法,即可以嵌入java代码。
jsp脚本片段:<% java代码 %>
jsp表达式: <%=变量或者等式%>
jsp声明: <%! %>—会被编译到jsp对应的java文件的类中,其他的就会生成到jspService的方法中。
JSP的注释在客户端不显示,HTML注释会显示。
4.4 JSP指令
<%@page args.... %>
<%@include file="" %> ---->公有信息可以这么导入,比如网页的头部和脚部,相当于吧代码导入
JSP标签
<jsp:include page=""> 本质是拼接页面,所以其他文件中的变量与本文件有重名也可以
4.5 9大内置对象
- PageContext
- Request
- Resopnse
- Session
- Application(ServletContext)
- config(ServletConfig)
- out
- page
- exception
4.6、JSP标签,JSTL标签,EL表达式
依赖
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
EL表达式:${ }
JSP标签
<jsp:forward page="/jsptag2.jsp">
<jsp:param name="name" value="小名"/>
<jsp:param name="age" value="19"/>
</jsp:forward>
JSTL标签
参考:https://www.runoob.com/jsp/jsp-jstl.html
在tomcat中也需要引入jstl的包
5、JavaBean
实体类
JavaBean有特定的写法:
- 必须有一个无参构造
- 属性必须私有化
- 必须有对应的get/set方法
一般用来和数据库的字段做映射ORM
ORM:对象关系映射
6、MVC三层架构
MVC:Model view Controller 模型、视图、控制器
6.1、早些年
用户直接访问控制层,控制层可以直接操作数据库
弊端:程序臃肿,不利于维护
6.2、MVC三层
Model
- 业务处理:业务逻辑(Service)
- 数据持久层:CRUD(Dao)
View
Controller
7、Filter(重点)
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
8、监听器
实现监听器
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);
}
}
9、JDBC
jdbc:java连接数据库
jar包支持
- java.sql
- javax.sql
- mysql-conneter-java 连接驱动,必须要导入
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 = "*******";
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, username, password);
Statement statement = connection.createStatement();
String sql = "select * from student";
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"));
}
rs.close();
statement.close();
connection.close();
事物
要么都成功,要么都失败
ACID原则:保证数据的安全
开启事物
事物提交 commit()
事物回滚 rollback()
关闭事物
connection.setAutoCommit(false);
Junit:单元测试
简单使用
@Test注解只有在方法上有效,只要加了这个注解就可以直接运行。
————----————JavaWeb完结——————————
拓展
10、文件上传
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (!ServletFileUpload.isMultipartContent(req)){
return;
}
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();
}
try {
DiskFileItemFactory factory = getDiskFileItemFactory(tmpFile);
ServletFileUpload upload = getServletFileUpload(factory);
String msg = uploadParseRequest(upload,req,uploadPath);
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);
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 = "";
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 + "]");
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目录下。
11、邮件发送
11.1、普通邮件发送
纯文本邮件发送
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");
prop.setProperty("mail.transport.protocol","smtp");
prop.setProperty("mail.smtp.auth","true");
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable","true");
prop.put("mail.smtp.ssl.socketFactory",sf);
Session session=Session.getDefaultInstance(prop, new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("mrneo@foxmail.com","qpszlppmatiweiaa");
}
});
session.setDebug(true);
Transport ts=session.getTransport();
ts.connect("smtp.qq.com","mrneo@foxmail.com","qpszlppmatiweiaa");
MimeMessage message=new MimeMessage(session);
message.setFrom(new InternetAddress("mrneo@foxmail.com"));
message.setRecipient(Message.RecipientType.TO,new InternetAddress("mrneo@foxmail.com"));
message.setSubject("发送的标题");
message.setContent("内容","text/html;charset=UTF-8");
ts.sendMessage(message,message.getAllRecipients());
ts.close();
}
}
11.2、复杂邮件发送
带有附件的邮件发送
public class SendMail3 {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.setProperty("mail.host","smtp.qq.com");
properties.setProperty("mail.transport.protocol","smtp");
properties.setProperty("mail.smtp.auth", "true");
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", sf);
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("mrneo@foxmail.com","qpszlppmatiweiaa");
}
});
session.setDebug(true);
Transport tp = session.getTransport();
tp.connect("smtp.qq.com","mrneo@foxmail.com","qpszlppmatiweiaa");
MimeMessage mimeMessage = imageMail(session);
tp.sendMessage(mimeMessage,mimeMessage.getAllRecipients());
tp.close();
}
public static MimeMessage imageMail(Session session) throws MessagingException {
MimeMessage mimeMessage = new MimeMessage(session);
mimeMessage.setFrom(new InternetAddress("mrneo@foxmail.com"));
mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("mrneo@foxmail.com"));
mimeMessage.setSubject("我也不知道是个什么东西就发给你了");
MimeBodyPart body1 = new MimeBodyPart();
body1.setDataHandler(new DataHandler(new FileDataSource("src/resources/1.png")));
body1.setContentID("yhbxb.png");
MimeBodyPart body2 = new MimeBodyPart();
body2.setContent("请注意,我不是广告<img src='cid:yhbxb.png'>","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");
MimeBodyPart contentText = new MimeBodyPart();
contentText.setContent(multipart1);
MimeMultipart allFile =new MimeMultipart();
allFile.addBodyPart(body3);
allFile.addBodyPart(body4);
allFile.addBodyPart(contentText);
allFile.setSubType("mixed");
mimeMessage.setContent(allFile);
mimeMessage.saveChanges();
return mimeMessage;
}
}
JavaWeb实现邮件发送:https://blog.csdn.net/qq_54897873/article/details/118557180
使用多线程,防止出现耗时,和网站注册人数过多的情况;
12、Maven
maven的常见问题,资源导出失败
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
|