Servlet
本身启动tomcat打开的是webapp/WEB-INF/index.jsp静态的文件,若在web-xml文件中加入servlet,并进行mapping映射,在映射中起名,映射的请求路径,tomcat会走动态页面流程,通过url加入网址为进入口,mapping中的name进行链接servlet,在serevlet中的class进入类中,识别是否继承HttpServlet,之后进行doget方法进行返回页面状态(初期个人理解)
Servlet接口sun公司有两个默认的实现类:httpservlet,GenericServlet
Servlet:把实现了servlet接口的java程序叫做servlet
1.2、helloservlet
1.构建一个普通的maven项目,删除里面的src目录,以后学习就用该项目里建立moudle,这个空的工程就是maven主工程
2.关于maven父子工程的理解:
父项目中会有:
<modules>
<module>servlet-01</module>
</modules>
子项目中会有:
<parent>
<artifactId>javaweb-02-servlet</artifactId>
<groupId>com.cheng</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的java子项目可以直接使用
3.编写一个servlet程序
1.编写一个普通类
2.实现servlet接口,这里我们直接继承httpservlet
一个类写好
public class HelloServlet extends HttpServlet {
//由于get或者post只是请求实现的不同方式,可以互相调用,业务逻辑都一样
@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映射
6.编写servlet的映射
为什么需要映射:我们写的是java程序,但是要通过浏览器访问,而浏览器需要链接web服务器,所以我们需要在web服务器中注册我们写的servlet,还需给他一个刘侃奇能够访问的路径;
<!--注册servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.cheng.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet的请求路劲-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
7、配置toncat
8、servlet原理
从浏览器发出请求到web容器,web容器将rqquest请求在servlet接口的service类的servicerequest方法处理,并作出响应在传回response到web容器中,web容器在返回黑页面
6.4、mapping的问题
1.一个servlet可以指定一个映射路径<url-pattern>/hello</url-pattern>
2.一个servlet可以指定对个映射的路径<url-pattern>/hello</url-pattern>或者<url-pattern>/hello1</url-pattern>或者<url-pattern>/hello3</url-pattern>都可以
3.一个servlet可以指定通用映射路径<url-pattern>/hello/*</url-pattern>
4.默认路径<url-pattern>/*</url-pattern>
5.指定一些后缀或者前缀等等。。。。<url-pattern>*/cheng</url-pattern>
6.优先级问题
指定了固有的映射路径优先级最该高,如果找不到就会走默认的处理请求
6.5、ServletContext共享数据
Web容器在启动的时候,他会为每个web应用都创建一个对应的servletcontext对象,它代表了当前的web应用;
Getinitparameter() 初始化参数
Getservletconfig() servlet配置
Getservletcontext() servlet上下文
第一个web写入
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String username="cheng";
servletContext.setAttribute("username",username);//将一个数据保存在了ServletContext
}
第二个web使用
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String username = (String) servletContext.getAttribute("username");
resp.setContentType("text/html");//转义字符
resp.setCharacterEncoding("utf-8");//转义字符
resp.getWriter().print("名字"+username);
}
转发
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
System.out.println("进入了方法");
RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");//转发的请求路径
requestDispatcher.forward(req,resp);//调用forward实现请求转发
}
转发就是A需要资源,而C有,A问B要,B从C那拿过来再给A
重定向是A需要资源,而C有,A问B要,B说C有让A去C那拿,于是A去C那拿了
这也就是问什么转发的url没变化,重定向url会发生变化
4、读取资源文件
Properties
- 在java目录下新建properties
- 在resources目录下新建properties
发现:都被打包到了一个路径下:classes,我们俗称这个路径为classpath
思路:需要一个文件流
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/cheng/servlet/aa.properties");
Properties prop = new Properties();
prop.load(is);
String user = prop.getProperty("username");
String pwd = prop.getProperty("password");
resp.getWriter().print(user+":"+pwd);
}
6.6、HttpServletResponse
Web服务器接收到客户端的其请求,针对请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse对象
- 如果要获取客户端请求过来的参数:找HttpServletRequest
- 如果要给客户端响应一些信息:找HttpServletResponse
2、常见应用
1.向浏览器输出信息()
2.下载文件
1.要获取下载文件的路径
2.下载的文件名
3.设置想办法让浏览器能够支持下载需要的东西
4.获取下载文件的输入流
5.创建缓冲区
6.获取OutputStream对象
7.将FileOutputStream流写入到buffer缓冲区
8.使用OutputStream将缓冲区中的数据输出到客户端
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.要获取下载文件的路径
String realPath ="F:\\idea文件作业\\javaweb-02-servlet\\response\\target\\classes\\1.JPG";
System.out.println("要获取下载文件的路径"+realPath);
// 2.下载的文件名
String substring = realPath.substring(realPath.lastIndexOf("//") + 1);
// 3.设置想办法让浏览器能够支持(Content-disposition)下载需要的东西
resp.setHeader("Content-disposition","attachment;filename="+URLEncoder.encode(substring,"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);
}
in.close();
out.close();
}
3、验证码功能
- 前端实现
- 后端实现,需要用到java的图片类,生成一个图片
- @Override
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.blue);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.black);
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());
}
4、重定向
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/image");//重定向
}
6.7、HttpServletRequest
1.获取前端传入的参数
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//后台接收中文乱码问题
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println(username+":"+password);
System.out.println(Arrays.toString(hobbys));
//通过请求转发
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
7、cookie、session
会话:用户打开一个浏览器,点击或访问web资源,然后关闭浏览器,这个过程称为会话;
有状态会话:证明客户端曾经浏览过该网页称之为有状态会话
客户端 服务端
- 服务端给客户端一个信件,客户端下次访问服务器带上信息就可以;cookie
- 服务器登记客户端来过,下次客户端在来,服务端就进行匹配该客户端;session
7.2、保存会话的两种技术
Cookie
客户端技术(响应,请求)
Session
服务器技术,保存用户会话信息
7.3、cookie
1.从请求中拿到cookie信息
2.服务器响应给客户端cookie
req.getCookies();//获得cookie
cookie.getName();//获得cookie中的key
cookie.getValue();//获得cookie中的value
new Cookie("lastlogintime",System.currentTimeMillis()+"");新建一个cookie
cookie.setMaxAge(24*60*60);设置cookie有效期
resp.addCookie(cookie);响应给客户端一个cookie
7.4、Session(重点)
什么是session:
- 服务器会给每一个用户(浏览器)创建一个session对象
- 一个session独占一个浏览器,只要浏览器没有关闭,这个session就存在
- 用户登录之后,整个网站它都可以进行访问!->保存用户的信息;保存购物车的信息
- //得到session
HttpSession session = req.getSession();
//给session中存东西
session.setAttribute("name",new Person("程",1));
//获取session的ID
String sessionid = session.getId();
//判断session是不是新创建的
if (session.isNew()){
resp.getWriter().write("session创建成功,session的ID为:"+sessionid);
}else {
resp.getWriter().write("session已经在服务器存在了,session的ID为:"+sessionid);
} - //得到session
HttpSession session = req.getSession();
Session的注销
HttpSession session = req.getSession();
session.removeAttribute("name");
session.invalidate();//注销
会话自动过期在web.xml中配置
<session-config>
<!--1分钟后session失效-->
<session-timeout>1</session-timeout>
</session-config>
Session和cookie的区别:
- Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
- Session把用户的数据写到用户独占session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)
- Session对象有服务器创建
8、JSP
8.1、什么是SJP
Java server pages:java服务器端页面,也和servlet一样,用于动态web技术!
最大的特点:
- HTML只给用户提供静态的数据
- JSP页面可以嵌入java代码,为用户提供动态数据
8.2、JSP原理
JSP本质上就是一个servlet
用户通过电脑发送请求道服务器调取页面,服务器在web容器中将JSP最终转换为class给服务器在,服务器在响应给用户
在JSP页面中:
只要是JAVA代码就会原封不动的输出;
如果是HTML代码,就会转换成:
Out.write(“<html>\r\n”)
这样的格式输出到前端
8.3、JSP基础语法
<%--JSP表达式:
作用:用来将程序的输出,输出到客户端
公式:
<%=变量或表达式%>
--%>
<%=new java.util.Date()%>
脚本片段
<%
int sum=0;
for (int i = 1; i <=100; i++) {
sum+=i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>
JSP的注释,不会在客户端显示,HTML就会
8.4、JSP指令
<%@page errorPage="error/500.jsp" %>定制错误页面
<%@include file=""%>抽取网页固定部分
Jsp语法
<%@include file="common/header.jsp"%>
<h1>主体</h1>
<%@include file="common/footer.jsp"%>
<hr>
<jsp:include page="/common/header.jsp"></jsp:include>
<h1>主体</h1>
<jsp:include page="common/footer.jsp"></jsp:include>
8.5、9大内置对象
- PageContext用于存东西
- Request用于存东西
- Response
- Session可以存东西
- Application[ServletContext]用于存东西
- Config[ServletConfig]
- Out
- Page
- exception
pageContext.setAttribute("name1","程1");//保存的数据只在一个页面中有效
request.setAttribute("name2","程2");//保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","程3");//保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","程4");//保存的数据只在服务器中有效,从打开服务器到关闭服务器
request:客户端向服务器发送请求,产生的数据,用户看完就没用了,例如:新闻,用户看完就没用了
session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据
8.6、JSP标签,JSTL标签,EL表达式
导入所用包
<!-- JSTL表达式的依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
EL表达式:${}
- 获取对象
- 执行运算
- 获取web开发的常用对象
- 调用java方法
JSP标签
<%request.setCharacterEncoding("utf-8");%>
<%--<jsp:include page=""></jsp:include>--%>
<jsp:forward page="/jsptag2.jsp">
<jsp:param name="name1" value="程1"></jsp:param>
<jsp:param name="name2" value="程2"></jsp:param>
</jsp:forward>
JSTL表达式
JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义许多标签,可以供我们使用,标签的功能和java代码一样
<c:out> 用于在JSP中显示数据,就像<%= ... >
<c:set> 用于保存数据
<c:remove> 用于删除数据
<c:catch> 用来处理产生错误的异常状况,并且将错误信息储存起来
<c:if> 与我们在一般程序中用的if一样
<c:choose> 本身只当做<c:when>和<c:otherwise>的父标签
<c:when> <c:choose>的子标签,用来判断条件是否成立
<c:otherwise> <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行
<c:import> 检索一个绝对或相对 URL,然后将其内容暴露给页面
<c:forEach> 基础迭代标签,接受多种集合类型
<c:forTokens> 根据指定的分隔符来分隔内容并迭代输出
<c:param> 用来给包含或重定向的页面传递参数
<c:redirect> 重定向至一个新的URL.
<c:url> 使用可选的查询参数来创造一个UR
JSTL标签的使用步骤
- 引入对应的taglib
- 使用其中的方法
- 在Tomcat也要引入jstl的包,否则会报错:jstl解析错误
- <h1>测试</h1>
<form action="coreif.jsp" method="get">
<%--
EL表达式获取表单中的数据
${param.参数名}
--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<c:if test="${param.username=='admin'}" var="isAdmin">
<c:out value="管理员欢迎"/>
</c:if>
<c:out value="${isAdmin}"/>
判断
<%--定义一个变量score,值为85--%>
<c:set var="score" value="85"/>
<c:choose>
<c:when test="${score>=90}">
<h1>你的成绩优秀</h1>
</c:when>
<c:when test="${score>=80}">
<h1>你的成绩优秀</h1>
</c:when>
<c:when test="${score>=70}">
<h1>你的成绩优秀</h1>
</c:when>
<c:when test="${score<=60}">
<h1>你的成绩优秀</h1>
</c:when>
</c:choose>
C:Foreach
<%
ArrayList<String> people = new ArrayList<>();
people.add(0,"一");
people.add(1,"二");
people.add(2,"四");
people.add(3,"五");
request.setAttribute("list",people);
%>
<%--
var,每一次遍历的对象
items,要遍历的对象
--%>
<c:forEach var="people" items="${list}">
<c:out value="${people}"/><br>
</c:forEach>
<hr>
<%--
var,每一次遍历的对象
items,要遍历的对象
begin,从那个开始
end,到哪为止
step,步长
--%>
<c:forEach var="people" items="${list}" begin="1" end="2" step="2">
<c:out value="${people}"/><br>
</c:forEach>
9、JavaBean
实体类
JavaBean有特定的想法:
- 必须要有一个无参构造
- 属性必须私有
- 必须有对应的get/set方法
一般用来和数据库字段做映射 ORM
ORM:对象关系映射
- 表----à类
- 字段-----à属性
- 行纪录-----à对象
10、MVC三层架构
什么是MVC:Model view Controller 模型、视图、控制器
Model
- 业务处理:业务逻辑(service)
- 数据持久层:CRUD(Dao)
View
- 展示数据
- 提供链接发起Servlet请求(a,form,img….)
Controller(Servlet)
- 接收用户的请求:(req:请求的参数,session信息)
- 交给业务层处理对应的代码
- 控制视图的跳转
11、Filter过滤器
用于过滤网站的数据:
- 处理中文乱码
- 登录验证…….
Filter开发步骤:
1.导报
2.编写过滤器
实现接口Filter是java.servlet的
实现Filter接口,重写对应方法
public class CharacterEncodingFilter implements Filter {
//初始化:web服务器启动,就已经初始化了,随时等待过滤对象出现
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter初始化");
}
//chain:链
// 1.过滤中的所有代码,在过滤特定请求的时候都会执行
// 2.必须要让过滤器继续通行
// chain.doFilter(request,response);
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");
System.out.println("CharacterEncodingFilter执行前。。。");
chain.doFilter(request,response);//让我们的请求继续走,如果不写,程序就会被拦截停止
System.out.println("CharacterEncodingFilter执行后。。。");
}
//销毁:web服务器关闭的时候进行销毁
public void destroy() {
System.out.println("CharacterEncodingFilter销毁");
}
}
在web.xml中配置filter
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.cheng.Filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--过滤只要是/servlet的任何请求,就会经历这个过滤器-->
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
12、监听器
编写监听器,实现监听器接口
public class OnlineCountListener implements HttpSessionListener {
//创建session监听:看你的一举一动
//一旦创建一个session就会触发这个实践
public void sessionCreated(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
System.out.println(se.getSession().getId());
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);
}
//销毁session监听
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);
}
}
13、过滤器、监听器常见应用
1.导入数据库依赖
2.链接数据库,并抽取数据
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//配置信息
String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
String username="root";
String password="123456";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3.向数据库发送sql的statement
Statement statement = connection.createStatement();
//4.编写sql
String sql="select * from users";
//5.执行sql,返回一个结果集ResultSet
ResultSet rs = statement.executeQuery(sql);
while (rs.next()){
System.out.println("id="+rs.getObject("id"));
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("birthday="+rs.getObject("birthday"));
}
//6.关闭链接
rs.close();
statement.close();
connection.close();
}
JDBC步骤:
- 加载驱动
- 连接数据库,代表数据库
- 向数据库发送SQL的对象Statement:CRUD
- 编写SQL(根据业务,不同的SQL)
- 执行SQL
- 关闭链接
预编译sql
public static void main(String[] args) throws Exception {
//配置信息
String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
String username="root";
String password="123456";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3.编写sql
String sql="insert into users(id, name, password, email, birthday) VALUES (?,?,?,?,?)";
//4.预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,5);//给第一个占位符添值
preparedStatement.setString(2,"yang");
preparedStatement.setString(3,"123456");
preparedStatement.setString(4,"46245256@qq.com");
preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));
//5.执行sql
int i = preparedStatement.executeUpdate();
if (i>0){
System.out.println("插入成功");
}
//6.关闭链接
preparedStatement.close();
connection.close();
}
事务
要么都成功,要么都失败
ACID原则:保证数据的安全
Junit单元测试
依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
测试使用@Test
项目的搭建
- 搭建一个maven web项目
- 配置toncat
- 测试项目是否可以跑起来
- 导入jar包
Jsp,servlet,mysql驱动,jstl,stand…….
5.创建项目包结构
6.编写实体类
7.编写基础公共类
1.数据库配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username=root
password=123456
-
- 编写字符编码过滤器
8、导入静态资源
登录功能
1、设置欢迎页(启动tomcat就是登录页)
<!--设置欢迎页面-->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
2.编写dao层登录用户登录的接口
//得到登录的用户
public User getLoginUser(Connection connection, String userCode) throws SQLException;
3.编写dao接口的实现类
public class UserDaoImpl implements UserDao {
public User getLoginUser(Connection connection, String userCode) throws SQLException {
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);
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.setCreattionDate(rs.getDate("creationDate"));
user.setModifyBy(rs.getInt("modifyBy"));
user.setModifyDate(rs.getDate("modifyDate"));
}
BaseDao.closeResources(null,pstm,rs);
}
return user;
}
}
- 业务层接口
- //用户登录
public User Login(String userCode,String password);
6.业务层实现类
public class UserServiceImpl implements UserService{
//业务层都会调用dao层,所以我们要引入Dao层
private UserDao userDao;
public 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.closeResources(connection,null,null);
}
return user;
}
7.编写sevlet
@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");
//和数据库中的密码进行对比,
UserServiceImpl 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);
}
注册servlet
<!--servlet-->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.cheng.servlet.user.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
测试访问,确保以上功能
登录功能优化
注销功能
思路:移除session,返回登录页面
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//移除用户的session
req.getSession().removeAttribute(Constants.USER_SESSION);
resp.sendRedirect("/login.jsp");//返回登录页面
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
登录拦截优化
public class SysFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//从session中获取用户
User user = (User) request.getSession().getAttribute(Constants.USER_SESSION);
if (user==null){//已经被移除或注销,或未登录
response.sendRedirect("/error.jsp");
}else {
filterChain.doFilter(servletRequest,servletResponse);
}
}
public void destroy() {
}
}
密码修改
- UserDao接口
- //修改当前用户的密码
public int updatepwd(Connection connection,int id,int password)throws SQLException; - 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.closeResources(null, pstm, null);
}
return execute;
}
- UserService层接口
- //根据用户id修改密码
public boolean updatepwd( int id, int pwd); - 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.closeResources(connection,null,null);
}
return flag;
}
- servlet层
- //从session里获取id
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String newpassword = req.getParameter("newpassword");
System.out.println("UserServlet"+newpassword);
boolean flag=false;
if (o!=null && newpassword!=null){
UserService userService = new UserServiceImpl();
flag = userService.updatepwd(((User) o).getId(), newpassword);
if (flag){
req.setAttribute("message","修改密码成功,请退出,使用新密码登录");
//密码修改成功,移除当前session
req.getSession().removeAttribute(Constants.USER_SESSION);
}else {
req.setAttribute("message","密码修改失败");
}
}else {
req.setAttribute("message","新密码有问题");
}
try {
req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
8.使用复用,提取方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if (method.equals("savepwd")&& method!=null){
this.updatePwd(req,resp);
}
}
优化密码修改使用Ajax
1.阿里巴巴的fastjson
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
用户管理实现
- 导入分页的工具类
- 用户列表页面导入
获取用户数量
- userDao
- //根据用户名或者角色查询用户总数
public int getUserCount(Connection connection,String username,int userRole)throws SQLException;
- userDaoImpl
- //根据用户名或者角色查询用户总数
public int getUserCount(Connection connection, String username, int userRole) throws SQLException {
PreparedStatement pstm=null;
ResultSet rs=null;
int count=0;
if (connection!=null){
StringBuffer sql=new StringBuffer();
sql.append("select count(1) as count from smbms_user u,smbms_role r where u.userRole=r.id");
ArrayList<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);
}
//怎么把list转换为数组
Object[] params = list.toArray();
System.out.println("UserDaoImpl-->getUserCount:"+sql.toString());//输出完整的sql语句
rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
if (rs.next()){
count = rs.getInt("count");//从结果集中获取最终数量
}
BaseDao.closeResources(null,pstm,rs);
}
return count;
} - UserService
- //查询记录数
public int getUserCount(String username,int userRole); - UserServiceImpl
- //查询记录数
public int getUserCount(String username, int userRole) {
Connection connection = null;
int count=0;
try {
connection = BaseDao.getConnection();
count = userDao.getUserCount(connection, username, userRole);
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResources(connection,null,null);
}
return count;
}
获取用户列表
- Userdao
- //获取用户列表
public List<User> getUserList(Connection connection,String userName,int userRole,int currenPageNo,int pageSize)throws SQLException, Exception; - Userdaoimpl
- //获取用户列表
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize)throws Exception {
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);
}
//在mysql数据库中,分页使用 limit startIndex,pageSize ; 总数
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.closeResources(null, pstm, rs);
}
return userList;
}
- Userservice
- //根据条件查询用户列表
public List<User> getUserList(String queryUserName,int queryUserRole,int currentPageNo,int pageSize); - Userserviceimpl
- public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize) {
Connection connection = null;
List<User> userList = null;
try {
connection = BaseDao.getConnection();
userList = userDao.getUserList(connection, queryUserName, queryUserRole, currentPageNo, pageSize);
} catch (Exception e) {
e.printStackTrace();
} finally {
BaseDao.closeResources(connection, null, null);
}
return userList;
}
获取用户操作
为了职责统一,可以把角色的操作单独放再一个包中,和entity类对应
- roledao
//获取角色列表
public List<Role> getRoleList(Connection connection)throws SQLException;
- roledaoimpl
//获取角色列表
public List<Role> getRoleList(Connection connection) throws SQLException {
PreparedStatement pstm=null;
ResultSet rs=null;
ArrayList<Role> roleList = new ArrayList<Role>();
if (connection!=null){
String sql="select * from smbms_role";
Object[] params={};
rs = BaseDao.execute(connection, pstm, rs, sql, params);
while (rs.next()){
Role _role=new Role();
_role.setId(rs.getInt("id"));
_role.setRoleName(rs.getString("roleNaem"));
_role.setRoleCode(rs.getString("roleCode"));
roleList.add(_role);
}
BaseDao.closeResources(null,pstm,rs);
}
return roleList;
}
- roleservice
//获取角色列表
public List<Role> getRoleList();
- roleserviceimpl
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.closeResources(connection,null,null);
}
return roleList;
}
- 用户显示Servlet
- 获取用户前端的数据(查询)
- 判断请求是否需要执行,看参数的值判断
- 为了实现分页,需要计算出当前页面和总页面,页面大小。。
- 用户列表展示
- 返回前端
文件上传
public class UploadFileServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//判断上传的表单是普通表单还是带文件的表单,是返回true,否返回false;
if (!ServletFileUpload.isMultipartContent(request)){
return;//如果这是一个普通文件我们直接返回
}//如果通过了这个if,说明我们的表单是带文件上传的
//创建上传文件的保存目录,为了安全建议在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 file = new File(tmppath);
if (!file.exists()){
file.mkdir();//如果目录不存在就创建这样临时目录
}
//处理上传的文件一般需要通过流来获取,我们可以通过request.getInputstream(),原生态文件上传流获取,十分麻烦
//但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖于common-io组件;
try {
//1、创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
DiskFileItemFactory factory = gteDiskFileItemFactory(file);
//2、获取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
//3、处理上传文件
String msg = uploadParseRequest(upload,request,uploadpath);
//Servlet请求转发消息
request.setAttribute("msg",msg);
request.getRequestDispatcher("/info.jsp").forward(request,response);
}catch (FileUploadException e){
e.printStackTrace();
}
}
public static DiskFileItemFactory gteDiskFileItemFactory(File file){
//1、创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
DiskFileItemFactory factory = new DiskFileItemFactory();
//通过这个工厂设置一个缓冲区,当上传的文件大小大于缓冲区的时候,将它放到临时文件中;
factory.setSizeThreshold(1024 * 1024);//缓冲区大小为1M
factory.setRepository(file);
return factory;
}
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
//2、获取ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
//监听文件上传进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long lpContentLenght, int i) {
//pBytesRead:已读取到的文件大小
//pContentLenght:文件大小
System.out.println("总大小:"+lpContentLenght+"已上传:"+pBytesRead);
}
});
//处理乱码问题
upload.setHeaderEncoding("UTF-8");
//设置单个文件的最大值
upload.setFileSizeMax(1024 * 1024 * 10);
//设置总共能够上传文件的大小
//1024 = 1kb * 1024 = 1M * 10 = 10M
upload.setSizeMax(1024 * 1024 * 10);
return upload;
}
public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest request,String uploadpath) throws IOException, FileUploadException {
String msg = "";
//3、处理上传文件
//把前端的请求解析,封装成一个FileItem对象
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()){ //判断是普通表单还是带文件的表单
//getFieldName指的是前端表单控件的name
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("")) continue;
//获得上传的文件名,例如/img/girl/ooa.jpg,只需要ooa,其前面的后面的都不需要
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
//获得文件的后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
/*
* 如果后缀名 fileExtName 不是我们需要的
*就直接return,不处理,告诉用户类型不对
* */
System.out.println("文件信息【文件名:"+fileName+"文件类型:"+fileExtName+"】");
//可以使用UUID(唯一通用识别码)来保证文件名的统一
String uuidFileName = UUID.randomUUID().toString();
//=======================传输文件=========================//
//获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
//创建一个文件输出流
FileOutputStream fos = new FileOutputStream(uploadpath + "/" + uuidFileName +"."+ fileExtName);
//创建一个缓冲区
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();//上传成功,清除临时文件
}
}
return msg;
}
}
邮件的发送实现
Session对象:定义整个程序所需要环境信息,比如主机名,端口,采用的邮件发送和接收协议
创建
Transport对象:用来发送邮件
引用
Message对象:表示一封电子邮件
邮件服务器
Store对象:用来接收邮件