文章目录
手写一个微型下载资源网站【Java实现用户注册、登陆、下载功能】
一、技术栈
语言:Java
Web:html + css + js +bootstrap
数据库:MySQL8.2
服务器:Tomcat
开发环境:JDK–1.8 、Servlet–3.0 、ntelliJ IDEA、Navicat-11
所需知识:javase、servlet、http、request、response、cookie、session、jsp+el+jstl、filter、listener
知识点详细总结链接:
02-JavaWeb开发【Tomcat服务器&Servlet接口&HTTP协议&HttpServletRequest&BeanUtils工具包封装请求数据&HttpServletResponse】
03-JavaWeb开发【最详细的Cookie&Session分析】
04-JavaWeb开发【JSP&EL&JSTL&MVC&Bootstrap前端框架】
05-JavaWeb的三大组件:小程序Servlet+过滤器Filter+监听器Listener
二、流程分析图
注册
登陆
下载
三、案例实现效果
页面没有太多美化修饰,具体以后端业务实现为主哦!
首页
注册
登陆
下载网主页
壁纸下载
书籍下载
影视下载
四、案例代码实现
注意事项
可先看,这些处理概念。后面开发时需要处理的细节。
一、将下载的文件放到WEB-INF下面,更安全,用户不会通过浏览器对其访问。
-------------------------------------------------------------
二、关于乱码问题:
首先要处理接收请求中文乱码问题:
request.setCharacterEncoding("utf-8");
然后解决响应给浏览器的乱码问题:
//解决响应体乱码问题
response.setContentType("text/html;charset=utf-8");
说明:上述只是解决响应体乱码问题,不能解决响应头乱码问题,由于告诉浏览器以附件形式下载,
使用的文件名在响应头中响应给浏览器,所以上述不能解决乱码问题。所以我们采用另外一种解决方案。
方案:URLEncoder按照UTF-8的编码方式对filename文件名进行编码。
//设置浏览器以附件形式下载
//对文件名编码
String encodeFilename = URLEncoder.encode(filename, "UTF-8");
response.setHeader("Content-Disposition","attachment;filename="+encodeFilename);
--------------------------------------------------------------
三、关于下载编写Servlet处理文件下载逻辑
1. 获取当前项目中资源的真实路径;
String realPath = getServletContext().getRealPath("/WEB-INF/"+filename);
2. 获取文件的mimeType;
String mimeType = getServletContext().getMimeType(fileName);
--------------------------------------------------------------
四、关于设置文件为附件的形式
对于response.setHeader("Content-Disposition","attachment;filename="+encodeFilename);
1.如果不加attachment关键字,则用户点击图片就可以直接在浏览器查看图片了,而我们的功能是下载。
所以要加attachment关键字,attachment表示附件的意思。
2.如果不书写 filename ,那么下载的文件名字就是当前servlet的路径名字。
3.【文件下载】两个响应头+流拷贝
1. 设置响应头: Content-Disposition // 告诉浏览器以附件的形式来处理文件;
2. 设置响应头: response.setContentType(mimeType) // 告诉浏览器下载的文件的类型;
3. 流拷贝:
1. 将文件读取到流里边: FileInputStream fin = new FileInputStream(file);
2. 将流写给浏览器:response.getOutputStream().write(arr,0,len);
1、数据库设计
create database user_managerment;
use user_managerment;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'zhangsan', '1234');
INSERT INTO `user` VALUES ('2', 'lisi', '1234');
INSERT INTO `user` VALUES ('3', 'wangwu', '1234');
INSERT INTO `user` VALUES ('4', 'zhaoliu', '1234');
2、项目结构
1)src
2)web
3)工具包
4)配置文件
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/user_managerment\
?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
jdbc.username=root
jdbc.password=1234
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--加载外部的配置文件-->
<properties resource="jdbc.properties"/>
<!--别名-->
<typeAliases>
<package name="cn.itcast.sh.login.pojo"/>
</typeAliases>
<!--mybatis环境的配置
一个核心配置文件,可以配置多个运行环境,default默认使用哪个运行环境
-->
<environments default="development">
<!--通常我们只需要配置一个就可以了, id是环境的名字 -->
<environment id="development">
<!--事务管理器:由JDBC来管理-->
<!--
事务管理器type的取值:
1. JDBC:由JDBC进行事务的管理
2. MANAGED:事务由容器来管理,后期学习Spring框架的时候,所有的事务由容器管理
-->
<transactionManager type="JDBC"/>
<!--数据源的配置:mybatis自带的连接池-->
<!--
数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源。
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--映射器-->
<mappers>
<!--加载其它的映射文件 注:注解开发是点号-->
<!--<package name="com.itheima.sh.dao"></package>-->
<!--
加载其它的映射文件 xml形式
包扫描方式加载mapper映射文件,说明:
1. 要求mapper映射文件,与mapper接口要放在同一个目录
2. 要求mapper映射文件的名称,与mapper接口的名称要一致
-->
<package name="cn.itcast.sh.login.dao"/>
</mappers>
</configuration>
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:/IdeaProjects/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout,file
5)web页面
index.jsp
<!DOCTYPE html>
<html lang="en">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 指定网页的字符集为utf-8-->
<meta charset="utf-8">
<!--使用微软最新的浏览器Edge的内核来解析当前的HTML文件,最新的浏览器都支持 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--
响应式布局参数:
viewport: 视口的参数
width=device-width:默认的网页宽度是设备的宽度
initial-scale=1: 初始的缩放比1:1
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<!-- 1. 导入bootstrap的全局css样式 -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<title>Beauty下载网</title>
</head>
<body>
<!--<div align="left">-->
<!-- <a href="register.jsp" class="btn btn-success">用户注册</a>-->
<!-- <a href="login.jsp" class="btn btn-primary">用户登陆</a>-->
<!--</div>-->
<h3 font-siz:200px align="center">Beauty下载网</h3>
<hr>
<div class="container">
<!-- 默认是白色,navbar-inverse 表示黑色-->
<nav class="navbar navbar-inverse">
<!-- container-fluid 表示占容器nav的100%-->
<div class="container-fluid">
<!-- navbar-header表示指定商标和开关的样式,让它在手机上更好的显示-->
<div class="navbar-header">
<!--开关按钮-->
<!--data-toggle="collapse" 表示点击按钮时可以折叠
data-target 点击开关按钮时,可以找到id是bs-example-navbar-collapse-1下拉菜单
而我们发现下面的下拉菜单的id正好是 bs-example-navbar-collapse-1
-->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1">
<!--开关按钮中的白线-->
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!--navbar-brand 表示商标 类似于苹果网站的苹果标志,无论设备窗口怎么变化,商标都会存在-->
<a class="navbar-brand" href="#">Beauty</a>
</div>
<!-- 下拉菜单,表单等 navbar-collapse 表示可以折叠的所有的项-->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active">
<span class="sr-only">(current)</span></a>
<a href="/register.jsp" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">注册
<!--向下箭头-->
</a>
</li>
<li class="dropdown">
<a href="/login.jsp" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">登陆
<!--向下箭头-->
</a>
</li>
<li class="dropdown">
<a href="/images.jsp" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">壁纸
<!--向下箭头-->
<span class="caret"></span></a>
<!--下拉项-->
<ul class="dropdown-menu">
<li><a href="#">风景</a></li>
<li><a href="#">美女</a></li>
<!--divider表示一条线-->
</ul>
</li>
<li class="dropdown">
<a href="/books.jsp" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">书籍
<!--向下箭头-->
<span class="caret"></span></a>
<!--下拉项-->
<ul class="dropdown-menu">
<li><a href="#">编程</a></li>
<li><a href="#">名著</a></li>
<!--divider表示一条线-->
</ul>
</li>
</li>
<!--dropdown表示下拉菜单-->
<li class="dropdown">
<a href="/movies.jsp" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">影视
<!--向下箭头-->
<span class="caret"></span></a>
<!--下拉项-->
<ul class="dropdown-menu">
<li><a href="#">电影</a></li>
<li><a href="#">动漫</a></li>
<!--divider表示一条线-->
</ul>
</li>
</ul>
<!--navbar-right表示form表单位于右侧-->
<form class="navbar-form navbar-right">
<div class="form-group">
<input type="search" class="form-control" placeholder="关键字">
</div>
<button type="submit" class="btn btn-default">搜索</button>
</form>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</div>
<br><br><br><br><br><br>
<div align="center" style="font-size: 17px">
<figure>
<div><a href="/login.jsp" target="_blank">
<span class="face">登陆</span>
<span class="face">Login</span></a>
</div>
</figure>
<br>
<figure>
<div><a href="register.jsp" target="_blank">
<span class="face">注册</span>
<span class="face">Register</span></a>
</div>
</figure>
<br>
<figure>
<div><a href="https://music.163.com/#/discover/toplist" target="_blank">
<span class="face">在线音乐</span>
<span class="face">Music</span></a>
</div>
</figure>
<br>
<figure>
<div><a href="#" target="_blank">
<span class="face">软件下载</span>
<span class="face">Software</span></a>
</div>
</figure>
<br>
<figure>
<div><a href="success.html" target="_blank">
<span class="face">网站主页</span>
<span class="face">Homepage</span></a>
</div>
</figure>
<br>
<div style="color: green">
<span class="face">网站当前在线</span>
<span class="face">${applicationScope.loginNumber}人</span></a>
</div>
</div>
<br><br>
<br><br>
<br><br>
<br><br>
<br><br><br><br><br>
<div class="footer" align="center" style="font-size: 16px">
<div class="foot_link">
<a href="#">关于作者</a>
<span>|</span>
<a href="#">联系作者</a>
<span>|</span>
<a href="#">招聘合作</a>
<span>|</span>
<a href="#">友情链接</a>
</div>
<p>CopyRight © 2021 上海菜鸟程序员研学中心 All Rights Reserved</p>
<p>电话:010-5211314 沪ICP备666888号</p>
</div>
<script src="js/canvas-nest.js"></script>
<!-- 2. 导入 jQuery 框架 -->
<script src="js/jquery-3.2.1.min.js"></script>
<!-- 3. 导入bootstrap框架 -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
register.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>注册页面</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/login.css" rel="stylesheet">
<script src="js/jquery.js"></script>
<script src="js/bootstrap.js"></script>
</head><%--
Created by IntelliJ IDEA.
User: cfl
Date: 2021/05/01
Time: 15:32
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>注册账户</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/login.css" rel="stylesheet">
<script src="js/jquery.js"></script>
<script src="js/bootstrap.js"></script>
</head>
<body>
<div align="left">
<a href="index.jsp" class="btn btn-success">首页</a>
</div>
<div class="container text-center">
<form class="form-signin" action="/registerServlet" method="post">
<h3 class="form-signin-heading">注册</h3>
<input type="text" name="username" class="form-control" placeholder="用户名" required autofocus>
<br>
<input type="password" name="password" class="form-control" placeholder="密码" required>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">注册</button>
</form>
<font color="red" size="2px">${requestScope.megRegister}</font>
</div>
</body>
</html>
<div class="container text-center">
<form class="form-signin" action="/registerServlet" method="post">
<h2 class="form-signin-heading">注册页面</h2>
<input type="text" name="username" class="form-control" placeholder="用户名" required autofocus>
<br>
<input type="password" name="password" class="form-control" placeholder="密码" required>
<br>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">注册</button>
</form>
</div>
</body>
</html>
login.jsp
<%--
Created by IntelliJ IDEA.
User: cfl
Date: 2021/04/27
Time: 23:24
To change this template use File | Settings | File Templates.
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>登录账户</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/login.css" rel="stylesheet">
<script src="js/jquery.js"></script>
<script src="js/bootstrap.js"></script>
<style type="text/css">
#cookie {
font-size: 2px;
}
#code {
border-collapse: collapse;
}
#code #codeImg {
padding: 1px 8px;
}
</style>
</head>
<body>
<div align="left">
<a href="index.jsp" class="btn btn-success">首页</a>
<a href="register.jsp" class="btn btn-info">注册</a>
</div>
<div class="container text-center">
<form class="form-signin" action="${pageContext.request.contextPath}/loginServlet" method="post">
<h3 class="form-signin-heading">登录</h3>
<input type="text" name="username" value="${cookie.username.value}" class="form-control" placeholder="用户名"
required autofocus>
<br>
<input type="password" name="password" value="${cookie.password.value}" class="form-control" placeholder="密码"
required>
<table id="code" align="left">
<tr>
<td>
<input type="text" name="checkCode"
class="form-control" placeholder="验证码" required>
</td>
<td id="codeImg">
<!--页面一加载就向checkCodeServlet发送请求-->
<img src="/checkCodeServlet" alt="验证码"
style="cursor: pointer" onclick="changeCheckCode(this);">
</td>
</tr>
</table>
<div align="left">
<table>
<tr>
<td>
<span id="cookie"><b>记住用户名密码:</b></span>
</td>
<td>
<input type="checkbox" name="checkbox">
</td>
</tr>
</table>
</div>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
</form>
<font color="red" size="2px">${requestScope.messageUser}</font>
<font color="red" size="2px">${requestScope.messageCode}</font>
</div>
<script type="text/javascript">
function changeCheckCode(obj) {
obj.src = "/checkCodeServlet?" + new Date().getTime();
}
</script>
</body>
</html>
success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<!-- nk rel="icon" href="../../favicon.ico">-->
<title>Beauty下载网</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/dashboard.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Beauty下载网</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li class="active"><a href="#">收藏<span class="sr-only">(current)</span></a></li>
<li><a href="#">设置</a></li>
<li><a href="#">帮助</a></li>
<li><a href="/LogoutServlet">退出</a></li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search...">
</form>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active"><a href="#">用户中心<span class="sr-only">(current)</span></a></li>
<li><a href="/images.jsp">壁纸下载</a></li>
<li><a href="/queryBooksServlet">书籍下载</a></li>
<li><a href="/movies.jsp">影视下载</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h3 class="page-header">个人信息</h3>
<div class="row placeholders">
<div class="col-xs-6 col-sm-3 placeholder">
<img src="img/demo.jpg" width="100" height="100" class="img-responsive" alt="Generic placeholder thumbnail">
<h5>username</h5>
<!-- <span class="text-muted">Something else</span>-->
</div>
</div>
<!-- <h2 class="sub-header">Section title</h2>-->
</div>
</div>
</div>
<script src="js/jquery.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery.js"><\/script>')</script>
<script src="js/bootstrap.js"></script>
</body>
</html>
books.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: cfl
Date: 2021/04/30
Time: 16:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<!--使用微软最新的浏览器Edge的内核来解析当前的HTML文件,最新的浏览器都支持 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--
响应式布局参数:
viewport: 视口的参数
width=device-width:默认的网页宽度是设备的宽度
initial-scale=1: 初始的缩放比1:1
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<!-- 1. 导入bootstrap的全局css样式 -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<title>书籍网</title>
<style>
tr{
height: 40px;
/*行文本居中*/
text-align: center;
}
table{
/*table表格在页面居中显示*/
margin: auto;
/*
border-collapse 属性设置表格的边框是否被合并为一个单一的边框
属性值是collapse:如果可能,边框会合并为一个单一的边框。会忽略 border-spacing 属性
*/
border-collapse: collapse;
}
</style>
</head>
<body>
<div align="left">
<a href="success.html" class="btn btn-success">首页</a>
</div>
<table border="1px" cellspacing="0" width="600">
<caption><h2>书籍列表</h2></caption>
<tr>
<th>编号</th>
<th>书籍名称</th>
<th>作者</th>
<th>价格</th>
</tr>
<%--使用jstl结合EL从后台queryAllServlet的reques域对象中取出数据--%>
<c:forEach items="${requestScope.bookList}" var="book">
<tr>
<td>${book.id}</td>
<td>${book.name}</td>
<td>${book.author}</td>
<td>${book.price}</td>
</tr>
</c:forEach>
</table>
<div align="center">
<h3>书籍下载</h3>
<a href="/downloadBookServlet?filename=红楼梦.txt">红楼梦</a><br>
<a href="/downloadBookServlet?filename=西游记.txt">西游记</a><br>
<a href="/downloadBookServlet?filename=JavaEE-SSH实战开发.txt">JavaEE-SSH实战开发</a><br>
<a href="/downloadBookServlet?filename=三国演义.txt">三国演义</a><br>
</div>
<!-- 2. 导入 jQuery 框架 -->
<script src="js/jquery-3.2.1.min.js"></script>
<!-- 3. 导入bootstrap框架 -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
images.jsp
<%--
Created by IntelliJ IDEA.
User: cfl
Date: 2021/05/02
Time: 19:43
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<!--使用微软最新的浏览器Edge的内核来解析当前的HTML文件,最新的浏览器都支持 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--
响应式布局参数:
viewport: 视口的参数
width=device-width:默认的网页宽度是设备的宽度
initial-scale=1: 初始的缩放比1:1
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<!-- 1. 导入bootstrap的全局css样式 -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<title>壁纸下载</title>
</head>
<body>
<div align="left">
<a href="success.html" class="btn btn-success">首页</a>
</div>
<br>
<h4 class="sub-header">壁纸下载</h4>
<hr>
<div align="center">
<a href="/downloadImageServlet?filename=刘亦菲.jpg">刘亦菲.jpg</a><br>
<a href="/downloadImageServlet?filename=壁纸.jpg">壁纸.jpg</a><br>
<a href="/downloadImageServlet?filename=小兔子.jpg">小兔子.jpg</a><br>
<a href="/downloadImageServlet?filename=01.jpg">01.jpg</a><br>
<a href="/downloadImageServlet?filename=02.txt">02.txt</a><br>
<a href="/downloadImageServlet?filename=03.zip">03.zip</a><br>
</div>
<!-- 2. 导入 jQuery 框架 -->
<script src="js/jquery-3.2.1.min.js"></script>
<!-- 3. 导入bootstrap框架 -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
movies.jsp
<%--
Created by IntelliJ IDEA.
User: cfl
Date: 2021/05/01
Time: 18:22
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>影视</title>
</head>
<body>
<a href="success.html">首页</a>
<h2>尚在开发中。。。。。</h2>
</body>
</html>
3、后端业务代码实现
1)test测试连接数据库
public static void main(String[] args) {
//获取session
SqlSession sqlSession = SessionFactoryUtil.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用方法查询数据
List<User> list = mapper.queryTest();
list.forEach(System.out::println);
sqlSession.close();
}
2)util工具
SessionFactoryUtil 工具类
/**
* 会话工厂工具类
1. 通过静态方法得到一个工厂对象
2. 通过静态方法得到会话对象
*
*/
public class SessionFactoryUtil {
//声明一个工厂对象
private static SqlSessionFactory factory;
//在静态代码块中创建会话工厂
static {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//得到输入流
try(InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");) {
factory = builder.build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
静态方法得到会话工厂
*/
public static SqlSessionFactory getSessionFactory() {
return factory;
}
/**
得到会话对象
*/
public static SqlSession getSqlSession() {
return factory.openSession();
}
}
Filter过滤器未登录拦截访问
LoginFilter
@WebFilter({"/success.html", "/books.jsp", "/movies.jsp", "/images.jsp"})
public class LoginFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
System.out.println("-----过滤登陆访问-----");
User user = (User) request.getSession().getAttribute("user");
if (user == null) {
/* request.getRequestDispatcher("/login.jsp")
.forward(request, response);*/
response.sendRedirect("/login.jsp");
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
Listener监听器统计网站在线人数
InitNumberListener
@WebListener
public class InitNumberListener implements ServletContextListener,
HttpSessionListener, HttpSessionAttributeListener {
// Public constructor is required by servlet spec
public InitNumberListener() {
}
// -------------------------------------------------------
// ServletContextListener implementation
// -------------------------------------------------------
public void contextInitialized(ServletContextEvent sce) {
System.out.println("-----初始化上下文对象-----");
ServletContext servletContext = sce.getServletContext();
servletContext.setAttribute("loginNumber", 0);
}
public void contextDestroyed(ServletContextEvent sce) {
}
// -------------------------------------------------------
// HttpSessionListener implementation
// -------------------------------------------------------
public void sessionCreated(HttpSessionEvent se) {
/* Session is created. */
}
public void sessionDestroyed(HttpSessionEvent se) {
/* Session is destroyed. */
}
// -------------------------------------------------------
// HttpSessionAttributeListener implementation
// -------------------------------------------------------
public void attributeAdded(HttpSessionBindingEvent sbe) {
}
public void attributeRemoved(HttpSessionBindingEvent sbe) {
}
public void attributeReplaced(HttpSessionBindingEvent sbe) {
/* This method is invoked when an attribute
is replaced in a session.
*/
}
}
LoginNumChangeListener
package cn.itcast.sh.login.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.*;
@WebListener
public class LoginNumChangeListener implements ServletContextListener,
HttpSessionListener, HttpSessionAttributeListener {
// Public constructor is required by servlet spec
public LoginNumChangeListener() {
}
// -------------------------------------------------------
// ServletContextListener implementation
// -------------------------------------------------------
public void contextInitialized(ServletContextEvent sce) {
}
public void contextDestroyed(ServletContextEvent sce) {
}
// -------------------------------------------------------
// HttpSessionListener implementation
// -------------------------------------------------------
public void sessionCreated(HttpSessionEvent se) {
/* Session is created. */
HttpSession session = se.getSession();
ServletContext servletContext = session.getServletContext();
Integer loginNumber = (Integer) servletContext.getAttribute("loginNumber");
servletContext.setAttribute("loginNumber", loginNumber+1);
}
public void sessionDestroyed(HttpSessionEvent se) {
/* Session is destroyed. */
HttpSession session = se.getSession();
ServletContext servletContext = session.getServletContext();
Integer loginNumber = (Integer) servletContext.getAttribute("loginNumber");
servletContext.setAttribute("loginNumber",loginNumber-1);
}
// -------------------------------------------------------
// HttpSessionAttributeListener implementation
// -------------------------------------------------------
public void attributeAdded(HttpSessionBindingEvent sbe) {
}
public void attributeRemoved(HttpSessionBindingEvent sbe) {
}
public void attributeReplaced(HttpSessionBindingEvent sbe) {
/* This method is invoked when an attribute
is replaced in a session.
*/
}
}
3)pojo实体类
User类
public class User {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Book类
public class Book {
private int id; //编号
private String name; //书名
private String author; //作者
private double price; //价格
//setter/getter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
4)dao层
UserMapper映射接口
public interface UserMapper {
@Select("select * from user")
List<User> queryTest();
@Select("select * from user where username=#{username} and password=#{password}")
User queryUserByUserNameAndPassword(User user);
@Insert("insert into user values(null,#{username},#{password})")
void register(User user);
}
BookMapper映射接口
public interface BookMapper {
@Select("select * from book")
List<Book> queryAllBooks();
}
5)service层
UserService业务处理
public class UserService {
// 注册业务逻辑处理
public boolean register(User user){
SqlSession sqlSession = null;
try {
sqlSession = SessionFactoryUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User us = userMapper.queryUserByUserNameAndPassword(user);
if(us == null){
userMapper.register(user);
sqlSession.commit();
return true;
}else {
return false;
}
}finally {
assert sqlSession != null;
sqlSession.close();
}
}
// 登陆业务逻辑处理
public boolean login(User user) {
//处理业务逻辑
//4. 通过会话工厂得到会话对象
SqlSession session = SessionFactoryUtils.getSqlSession();
//5. 会话对象得到UserMapper接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//接口对象调用方法
User loginUser = userMapper.queryUserByUserNameAndPassword(user);
session.close();
// 方式一
/* if (null == loginUser) {
return false;
}else {
return true;
}*/
// 方式二
// return loginUser == null ? false : true;
return loginUser != null;
}
}
BookService业务处理
public class BookService {
public List<Book> queryAllBooks(){
SqlSession sqlSession = SessionFactoryUtils.getSqlSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
List<Book> booksList = mapper.queryAllBooks();
sqlSession.close();
return booksList;
}
}
6)web层
CheckCodeServlet(生成验证码)
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("----请求验证码----");
/*
说明:验证码是一张图片,而这个图片中的内容是使用代码生成的。
分析和步骤:
1)创建一个可以存放图片的缓冲区BufferedImage作为画布;
2)通过画布获取到针对这个画布的画笔;
3)修改画布的背景颜色为白色;
4)设置画布的边框,画边框的时候需要注意下,如果这里写画布的宽width和高height ,就会超出画布就会看不见,所以width和height 分别-1;
5)创建一个获取随机数的对象;
6)给画布上写数据;
7)给画布上画干扰线;
8)需要把画布中的内容响应给浏览器;ImageIO.write(bi,"JPG",response.getOutputStream());
*/
//定义画布的宽和高
int width=120;
int height=30;
//创建一个可以存放图片的缓冲区,作为画布
//BufferedImage.TYPE_INT_RGB 表示生成图片的类型
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//通过画布获取到针对这个画布的画笔
Graphics g = bi.getGraphics();
//修改画布的背景颜色 每次使用画笔的时候都得给画笔指定颜色
g.setColor(Color.WHITE);
//填充画布
g.fillRect(0, 0, width, height);
//设置画布的边框
//给画笔指定颜色
g.setColor(Color.RED);
//给画布画边框 如果这里写width height 就会超过画布,因为边框也会占一个像素,所以这里宽和高都需要-1
g.drawRect(0, 0, width-1, height-1);
//创建一个获取随机数的对象
Random r = new Random();
//给画布上画干扰线
//循环控制画多条线
for(int i=1;i<=3;i++)
{
//设置画笔的颜色
g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
//向画布上画干扰线
//drawLine(x1, y1, x2, y2) 这里四个参数是因为两个点画成一条线
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
}
//定义数据准备向画布中写数据
String data="abcdefghigklmnpqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ123456789";
//创建字符串缓冲区
StringBuilder sb = new StringBuilder();
//循环控制画四个字符
for (int i = 1; i <=4; i++) {
//设置画笔的颜色 Color.BLUE这里的颜色固定了,只能是蓝色,我们可以让颜色随机变化
// g.setColor(Color.BLUE);
g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
//设置字体 Font.ITALIC表示斜体
g.setFont(new Font("宋体", Font.ITALIC, 20));
//给画布上写内容 20表示从x轴的位置开始书写 25表示y轴位置开始书写
// g.drawString("哈哈哈哈", 20, 25);
/*
* data.charAt()表示根据函数的参数进行查找字符
* data.length()表示字符串的长度
* r.nextInt()表示生成随机数,但是随机数的范围在0~data字符串的长度
*/
String str = data.charAt(r.nextInt(data.length())) + "";
g.drawString(str, 20*i, 25);
//将验证码内容拼接到字符串缓冲区中
sb.append(str);
}
// 验证码保存到session中
request.getSession().setAttribute("serverCheckCode",sb.toString());
//将生成的验证码图片响应给浏览器
ImageIO.write(bi,"JPG",response.getOutputStream());
}
}
RegisterServlet实现类
@WebServlet("/registerServlet")
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("---开始注册---");
//解决请求乱码
request.setCharacterEncoding("UTF-8");
//获取用户名
String username = request.getParameter("username");
System.out.println(username);
//获取密码
String password = request.getParameter("password");
System.out.println(password);
//创建业务层对象
UserService userService = new UserService();
//使用业务层对象调用方法注册
User user = new User();
user.setUsername(username);
user.setPassword(password);
boolean boo = userService.register(user);
//对boo结果进行判断
if (boo) {
//注册成功,跳转到登录页面,不需要携带数据
response.sendRedirect("/login.html");
} else {
//注册失败,跳转到注册失败页面或者输出一句话
// System.out.println("注册失败");
response.sendRedirect("/register.html");
}
}
}
LoginServlet实现类
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("登陆校验请求来了-------");
System.out.println(request.getMethod());
// 解码请求数据
request.setCharacterEncoding("utf-8");
// 获取用户输入的 用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
if(username == null && password == null){
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("<h2>请登录后再进入本网站!<h2>");
}
// 进行验证码校验
String checkCode = request.getParameter("checkCode"); // 获取用户输入的验证码
System.out.println(checkCode);
String serCode = (String) request.getSession().getAttribute("serverCheckCode"); // 获取服务器随机生成的验证码
System.out.println(serCode);
// 判断浏览器 验证码 与 服务器生成的验证码是否 相匹配 -》true 进行 用户验证
if(checkCode.equalsIgnoreCase(serCode)){
// 创建用户实体类
User user = new User();
user.setUsername(username);
user.setPassword(password);
// 调用用户名密码校验服务 进行校验
UserService userService = new UserService();
boolean loginResult = userService.login(user);
String resultStr = loginResult ? "用户登陆成功!" : "用户登陆失败!";
request.setAttribute("message", resultStr);
// 结果为true 用户存在 判断cookie 进入网站首页
// 否则 用户不存在 进入注册页面
if(loginResult){
// 判断用户是否记住cookie
String check = request.getParameter("checkbox");
System.out.println(check);
if("on".equals(check)){
Cookie cookieUserName = new Cookie("username", username);
Cookie cookiePassword = new Cookie("password", password);
response.addCookie(cookieUserName);
response.addCookie(cookiePassword);
}
/*request.getRequestDispatcher("/success.html")
.forward(request,response);*/
response.sendRedirect("/success.html");
}else {
/* request.getRequestDispatcher("/error.html")
.forward(request,response);*/
System.out.println(request.getAttribute("message"));
request.getRequestDispatcher("/loginErrorServlet")
.forward(request,response);
}
}else {
request.getRequestDispatcher("/login.html")
.forward(request,response);
}
}
}
LogoutServlet实现类
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("销毁session对象。。。。");
HttpSession session = request.getSession();
Cookie cookieUsername = new Cookie("username", "");
Cookie cookiePwd = new Cookie("password", "");
//2.设置cookie的存活时间是0
cookieUsername.setMaxAge(0);
cookiePwd.setMaxAge(0);
//3.设置cookie的有效路径和原来的有效路径一致
cookieUsername.setPath("/");
cookiePwd.setPath("/");
//4.响应给浏览器
response.addCookie(cookieUsername);
response.addCookie(cookiePwd);
// 销毁session
String username = request.getParameter("username");
session.invalidate();
System.out.println(username+"用户退出。。。。");
response.sendRedirect("/index.jsp");
}
}
DownloadImageServlet实现类
@WebServlet("/downloadImageServlet")
public class DownloadImageServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* String getRealPath(String path)
* 返回资源文件在服务器文件系统上的真实路径(文件的绝对路径)
* getMimeType(fileName)获取服务器中文件类型
*
ServletContext servletContext = getServletContext();
System.out.println(servletContext);
String mimeType = servletContext.getMimeType("壁纸.jpg");
System.out.println(mimeType); // image/jpeg
String realPath = servletContext.getRealPath("WEB-INF/壁纸.jpg");*/
System.out.println("---------开始接收客户端【下载文件】--------------");
// 1. 获取客户端下载的文件名
String filename = request.getParameter("filename");
System.out.println("filename:"+filename);
// 2. 获取servletContext上文对象
ServletContext servletContext = getServletContext();
// 3. 获取文件的真实路径
String realPath = servletContext.getRealPath("WEB-INF/"+filename);
System.out.println("realPath:"+realPath);
// 4. 创建下载文件的File对象
File file = new File(realPath);
System.out.println("文件对象:"+file);
// 5. 判断文件是否存在
if(file.exists()){
// 6. 存在,开始下载 把项目文件写入到浏览器通道 获取2个头 + 2 个流 【核心】
// 2个响应头 信息
// 获取 响应的 【文件类型】
String mimeType = servletContext.getMimeType(filename);
System.out.println("文件传输类型mimeType:"+mimeType); // image/jpeg
// 设置 响应的【浏览器文件类型】
response.setContentType(mimeType);
// 设置 浏览器以 【附件形式进行下载】, 如果文件名包含中文字符,首先进行编码
String encodeFilename = URLEncoder.encode(filename, "UTF-8");
response.setHeader("Content-Disposition","attachment;filename="+encodeFilename);
// 2个流【本地输入流】 【响应输出流】
// 创建字节输入流对象 -> 关联服务器文件 读取文件
FileInputStream fis = new FileInputStream(file);
// 获取响应对象的 输出流,向浏览器写入
ServletOutputStream os = response.getOutputStream();
// 7. 读取并写入文件数据 -》 给浏览器做出响应
byte[] buf = new byte[1024];
int len = 0;
while ((len=fis.read(buf))!= -1){
os.write(buf, 0, len);
}
// 8. 释放资源
fis.close();
os.close();
System.out.println("传送资源结束");
}else {
System.out.println(filename+"不存在");
}
}
}
QueryBooksServlet实现类
@WebServlet("/queryBooksServlet")
public class QueryBooksServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BookService bookService = new BookService();
List<Book> books = bookService.queryAllBooks();
request.setAttribute("bookList", books);
request.getRequestDispatcher("/books.jsp")
.forward(request,response);
}
}
下面两个请求处理可自行设计呀!
DownloadBookServlet
@WebServlet("/downloadBookServlet")
public class DownloadBookServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
DownloadMovieServlet
@WebServlet("/downloadMovieServlet")
public class DownloadMovieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
读到此处的小哥哥小姐姐们留个赞吧!加油
ღ( ´・ᴗ・` )比心