前言:
「? Design & Build 」
????????三个专业三个方向,共同完成一个项目,分别为:
????????物联网?? 数据库的搭建及管理员相关
????????电管?? ? ?硬件设施的实现
????????电商?? ? ?用户方面的前后端
????????在本次项目开发中,自身经历了从0到对前后端的基本完备了解与操作,以此记录一下长达一个月的开发流程。包括自己对于项目开发的一些理解和我遇到的问题及思考。
? ? ? ? 提前说明:在小学期之前,本人只有JavaEE的基础,对于web开发,网络协议,css,JavaScript等等没有任何了解,项目结束之后也才刚开始系统的学习相关知识,所以一些描述较为个人并不专业。
项目简介(电商方向):
? ? ? ?
????????要求开发Web应用程序
主要功能包括:
1. 与数据访问软件通信并检索/发送必要的信息。
2. 客户注册与登录
3. 显示家庭信息的当前状态与摘要(例如室内外温度的最低和最高时间段,设备的开关次数等)
更多功能包括但不限于:
1. 监测到任何欲动或任何窗户/门打开以供入室警报
2. 自主设计
项目理解:
????????与之前的C语言小学期一样,本质依然是对数据的操作,底层在于增删改查,上层在于显示。
????????只不过这次我们需要将数据存入数据库,这就涉及到数据库的设计,链接,数据规范等等。以及数据的显示从cmd变为web,这就涉及数据与网站的交互传输。这些为后端。
????????而关于数据怎么在web上面显示,这是前端。
项目开发
1.关键字
操作系统:MacOS
环境:IDEA(2021.2.1),MyEclipse ,HbuilderX
服务器:Tomcat(9.0.52)
后端:Java (1.8.0_221)
前端:Jsp,Html,Javascript,css
2.框架简介
?
?这里根据项目目录来介绍,左边为后端,右边为前端。
首先看左边
lib:jar包
src:后端的java文件
DAO:接口类,内部的Impl为对应的接口实现类
Email : 因为我在网页中添加了发送邮件的功能,所以这里建一个文件夹来存放相关函数
Entity :项目中类的集合,比如用户类,设备类,里面定义好了自己的属性,即他的数据应该如何存放,从而与数据库里的table进行交互
Servelt :里面的类全部extends HttpSevlet,即与jsp网页实现交互,进行数据传输的类
util :工具包,存放比如数据库连接类等
target:这个放在下面说,与IDEA的artifacts相关
右边:
html:html会定义页面的内容,比如在html里写入一个button,那么打开网页就回出现一个button。
css :css的作用为美化页面,比如你可以定义jsp和html网页中组件的颜色,样式,排版从而让他们更好看,比如button等等。
js :JavaScript作用为控制一些页面的行为,利用定义好的js函数,你可以直接在网页上实现一些操作,比如点击一个button,他的颜色发生改变。
images:需要在网页上显示的图片组件
webfonts:因为pc端之间的不同,所以显示组件肯定会有所不同,而webfonts里面的组件发布在网络上这就可以让pc统一访问来显示,比如字体。
assets:也是css和js
jsp:可以理解为html+java代码。jsp允许写入一些java代码从而进行数据的传输(即上面提到的Servlet类)。但是因为jsp的存在,这个项目并不能说成前后端分离的开发。
(tip:关于jsp和html的区别)
你可以直接将html代码复制到jsp里,然后加上jsp的开头即可。但是html是可以直接打开的,而jsp需要部署到服务器才能打开。这个也好理解,因为jsp允许写入java代码,来从后台读取数值,如果不发到服务器上便没办法传输这些数据,那么自然也就打不开。所以在开发前端过程中,你可以先利用html进行内部组件,css和js的调整来使得页面更加美观。页面调整完备后复制进jsp里,然后添加java代码进行相应的操作。这样效率较高,因为每次部署服务器都需要时间。
WEB-INF
?这个文件夹在创建web项目的时候自动生成,包括里面的web.xml。在配置环境的过程中,网上的教程都让在该目录下新建一个classes,来存放.java编译后的class,lib依然是需要的jar包。关于web.xml的作用,与之前提过的jsp与HttpServlet继承类之间的对应关系有关,我们需要把之间的映射关系写入这样才能搭建起联系。
3.开发流程
当了解完以上框架之后,我们清楚了一个完整的web项目内应该有什么,那么应该如何从0开始。
在我最开始的时候,这些我全部都不知道,只是在课上老师给了个demo,是登录验证,连接了数据库以得到用户信息,但是demo的框架在开发过程中一直没变。
随后我又找到几个完整项目的代码,包括前后端。
最后总结出来web项目的开发流程如下:
1. 首先根据需求建立数据库,并且构建好数据库规范,包括命名以及数据库范式。这确保数据的存取规范,而成功的数据库是可以避免很多SQLExeption的。
2. 根据数据库的table内的entity和attributes建立Entity类,统一命名及数据结构。比如用户类,我们就要统一用户变量,比如Id,邮箱,密码等等。(这个我在开发后期改了好几次,就是因为开始没有定义完善,以及当你定义完成员变量后,IDEA等所有主流IDE是支持自动generate getter和setter的。请一定要用自动生成而不是自己写,这样的命名较为规范。)
package Entity;
public class User {
private int userNo;
private String userEmail;
private String FName;
private String IName;
private String password;
private int familyNo;
public int getUserNo() {
return userNo;
}
public void setUserNo(int userNo) {
this.userNo = userNo;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getFName() {
return FName;
}
public void setFName(String FName) {
this.FName = FName;
}
public String getIName() {
return IName;
}
public void setIName(String IName) {
this.IName = IName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getFamilyNo() {
return familyNo;
}
public void setFamilyNo(int familyNo) {
this.familyNo = familyNo;
}
}
3. 然后我们需要与数据库进行连接 ,这里需要导入jdbc的jar包到lib里,然后配置好端口号等等,并且在util包内写好连接类,这里详细操作后续会说。
package util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnect {
private final String DBDRIVER = "com.mysql.cj.jdbc.Driver" ;
private final String DBURL = "jdbc:mysql://localhost/smarthome?useSSL=false&serverTimezone=UTC" ;
private final String DBUSER = "root" ;
private final String DBPASSWORD = "11111111" ;
public Connection conn = null ;
public DBConnect(){
try{
Class.forName(DBDRIVER) ;//指定连接类型
this.conn = DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD) ;//获取连接
}catch (Exception e){
e.printStackTrace();
}
}
public Connection getConnection() {
return this.conn;
}
//关闭数据库连接
public void close(){
try{
this.conn.close();
}catch (SQLException e){
e.printStackTrace();
}
}
}
4. 连接完成后,便需要通过Java来对数据库进行操作,而关于需要如何操作,先在接口类中定义好。 比如我需要用户登录,用户注册,用户注销等等。
package DAO;
import Entity.User;
public interface UserDAO {
public User userLogin(User user) throws Exception;
public int userLogout(User user) throws Exception;
public int userRegister(User user) throws Exception;
public int findEmail(String email) throws Exception;
public int userChange_password(User user) throws Exception;
}
5. 然后我们可以去Impl去具体完成接口,比如用户登录,我们需要去数据库查询账户与密码是否对应。而这个操作的本质其实就是增删改查中的查,用户注册就是增,用户注销就是删,以此类推,而这四种操作方式基本都一个模版,所以代码基本相似。但是功能是跟着需求走的,你需要通过SQL来找到你想要的数据。
public class UserDAOImpl implements UserDAO {
String sql= null ;
PreparedStatement pstmt = null;
DBConnect dbc = null ;
@Override
public User userLogin(User user) throws Exception {
int flag = 0;
User tempUser = null;
try {
sql="SELECT * FROM User WHERE userNo=? OR userEmail=? AND password=?";
dbc= new DBConnect();
pstmt = dbc.getConnection().prepareStatement(sql);
pstmt.setInt(1, user.getUserNo());
pstmt.setString(2, user.getUserEmail());
pstmt.setString(3,user.getPassword());
ResultSet rs=pstmt.executeQuery();
if(rs.next()) {
tempUser = new User();
tempUser.setUserNo(rs.getInt("userNo"));
tempUser.setUserEmail(rs.getString("userEmail"));
tempUser.setFName(rs.getString("FName"));
tempUser.setIName(rs.getString("IName"));
tempUser.setPassword(rs.getString("password"));
tempUser.setFamilyNo(rs.getInt("Family_familyNo"));
}
rs.close();
pstmt.close();
}catch(SQLException e) {
e.printStackTrace();
}finally {
dbc.close();
}
return tempUser;
}
}
?6. 我们根据账号密码从数据库得到相关信息后,我们需要从网站上得到用户输入的账号密码,那么就需要去jsp网页中添加输入的窗口,这里因为 以及添加了css样式所以不太好阅读,总之就是两个input框。这里需要定义好input的name值,因为表单转发后,servlet需要通过name来获取attributes的值。
<!--/Login-->
<div class="modal fade" id="exampleModalCenter2" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header text-center">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="login px-4 mx-auto mw-100">
<h5 class="text-center mb-4">Login Now</h5>
<form id="form_login" action="UserLogin" method="post">
<div class="form-group">
<label class="mb-2">userNo or Email address</label>
<label for="exampleInputEmail1"></label><input type="text" class="form-control" id="exampleInputEmail1" name="idOrEmail" aria-describedby="emailHelp" placeholder="" value="${idOrEmail}" required="">
<small id="emailHelp" class="form-text text-muted">We'll never share your information with anyone else.</small>
</div>
<div class="form-group">
<label class="mb-2">Password</label>
<label for="exampleInputPassword1"></label><input type="password" class="form-control" id="exampleInputPassword1" name="password" placeholder="" required="">
</div>
<button type="submit" id="loginBtn" class="btn btn-primary submit mt-2">Sign In</button>
<a style="color: #e2a0a0"> ${errorMsg_log} </a>
<div class="text-right pb-4">
<a href="EmailCode.jsp" data-toggle="modal2" data-target="#exampleModalCenter" > Forgot password </a>
<span style="color: #8c9398"> | </span>
<a href="userLogin.jsp" data-toggle="modal2" data-target="#exampleModalCenter" > Sign up</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!--//Login-->
?7.然后我们需要在段jsp代码中填入一个form标签并为其添加action与method。在上面这张图中的form的action是UserLogin,method是post。其作用是当用户输入完账号密码之后,点击摁钮,网站会将这些数据以表单的形式提交,然后根据action的url去之前提到的web.xml进行对应来转发表单数据到指定的servelt类中。这里的welcome-file-list可以理解为打开的第一个页面,下面的servlet与servlet-mapping必须是成对出现的。servlet-name上下一致,为了方便阅读一般都定义成相应的java文件名,当然也可以写成别的。servlet-class就是form转发表单所到的类,url-patten就是上面提到的form的action,当然这个命名也是自己定义的。这段代码的意义就是用户的登录信息通过为UserLogin的action被转发到UserServlet这个类中进行操作。
<welcome-file-list>
<welcome-file>/userLogin.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>UserLoginServlet</servlet-name>
<servlet-class>Servlet.UserLoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserLoginServlet</servlet-name>
<url-pattern>/UserLogin</url-pattern>
</servlet-mapping>
?8. 其实可以将Servlet类理解成那个连接web上传来的数据与数据库内数据进行交互的地方,这是一个连接口,比如在下面这段代码中我从表单中读取出了账号密码,然后去上面写好的DAOImpl函数去数据库进行查询看是否存在这个用户,如果存在则跳转到登录成功界面,失败则重新输入。当然我这段代码里还混合了查询家庭设备并传给web端。
package Servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import DAO.FamilyDAO;
import DAO.HwEDAO;
import DAO.Impl.FamilyDAOImpl;
import DAO.Impl.HwEDAOImpl;
import DAO.UserDAO;
import DAO.Impl.UserDAOImpl;
import Entity.HandwareEquipment;
import Entity.User;
public class UserLoginServlet extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException{
}
public void doPost(HttpServletRequest req,HttpServletResponse res)
throws IOException, ServletException{
User user = new User();
String idOrEmail = req.getParameter("idOrEmail");
String password = req.getParameter("password");
FamilyDAO familyDao = new FamilyDAOImpl();
HwEDAO hwedao=new HwEDAOImpl();
List<HandwareEquipment> result_list1 = null;
List<User> result_list2 = null;
int total=0;
int humidity=0;
int daw=0;
int brightness=0;
if(idOrEmail.contains("@")){
user.setUserEmail(idOrEmail);
user.setUserNo(-1);
}
else{
user.setUserNo(Integer.parseInt(idOrEmail));
user.setUserEmail("-1");
}
user.setPassword(password);
UserDAO dao = new UserDAOImpl();
User tempUser = null;
try {
tempUser = dao.userLogin(user);
}catch(Exception e) {
e.printStackTrace();
}
if(tempUser!=null) {
int familyNo=tempUser.getFamilyNo();
try{
total=hwedao.countTotal(familyNo);
humidity=hwedao.countHum(familyNo);
daw=hwedao.countDaW(familyNo);
brightness=hwedao.countBri(familyNo);
result_list1 = familyDao.queryHwE(familyNo);
result_list2 = familyDao.queryUser(familyNo);
}catch (Exception e){
e.printStackTrace();
}
HttpSession session = req.getSession();
session.setAttribute("userNo", user.getUserNo());
session.setAttribute("FName",tempUser.getFName());
session.setAttribute("IName",tempUser.getIName());
session.setAttribute("familyNo",tempUser.getFamilyNo());
if(result_list1!=null ||result_list2!=null) {
session.setAttribute("HwE_List", result_list1);
session.setAttribute("User_List",result_list2);
session.setAttribute("Total",total);
session.setAttribute("Humidity",humidity);
session.setAttribute("DaW",daw);
session.setAttribute("Brightness",brightness);
req.setAttribute("successMsg_homepage", "Please check the following information!");
res.sendRedirect("./Homepage.jsp");
}
else {
req.setAttribute("errorMsg_homepage", "No result in Database");
res.sendRedirect("./Homepage.jsp");
}
}
else {
req.setAttribute("errorMsg_log", "Error! Please try again!");
req.setAttribute("idOrEmail", idOrEmail);
req.getRequestDispatcher("./userLogin.jsp").forward(req, res);
}
}
}
?9.然后web收到信息后就会跳转到对应界面,我这里的后端逻辑为查询到用户匹配信息后会查到相应的家庭Id,然后进一步查询到家庭内设备信息,然后将这些数据打印出来。
?
?
10. 以上就是关于用户登录的整个开发流程,以此类推可以写出其他功能比如用户注册,设备查询等等。本质区别都在于对数据的操作。等这些功能实现后,就可以进行花里胡哨的操作了。因为我也同是负责了前端开发有些忙不过来,而我也没有系统的学过前端语言。于是就找了几个模版自己在上面修改。通过调整css里的配色及布局以达到自己想要的效果,增添一些js比如输入格式判断,也可以在后台添加一些花哨,我自己加了一个邮箱验证码的功能。
总之前端其实很简单,因为你可以看到<div>内是页面组件,而你只需要将你需要的组件替换掉模版内的组件,然后添加你自己的form,将name值全部定义好,这样就可以与后端连接起来。其实一般前端的代码都比较长,我找的模版大概六七千行,但其实比较有条理与逻辑,组件与组件之间是分开的。可以边看网页边看代码,耐着性子看一遍就知道怎么去修改。而且Chrome有Developer Tool,使得阅读源码更加方便。
4.开发中的问题(后续有空更)
- IDEA+Tomcat+JavaWEB 开发环境配置
- IDEA Artifacts 配置问题及报错 Couldn't copy ... to ...
- IDEA JAVA MySQL 连接
- Java Mail的实现
- 如何在JSP与后端传值及出现的NullPointerException等一系列问题
- HTML网页导入CSS和JS的路径问题
- 数据库内数据实时更新到页面上(WebSocket,Ajax两种方式)
结语
码字过程中又回顾了一下这几个月断断续续的开发过程,感谢自己硬着头皮接下来这么多活,不然其实也学不到这些东西。
但其实作为Web开发来说,上面这些技术大部分已经落后于时代,尤其是jsp。而关于为什么学习这些我也不知道,但是这个过程确实让我了解到一个网站的搭建。
我在开头说学校的课程安排并不合理,是因为我觉得,在只学了数据库与Java的情况下,就直接塞给这种任务。虽然是可以完成的,但在这个过程中磕磕绊绊,许多东西一知半解的做下来。而互联网协议与Socket编程等这些技术居然是安排在小学期之后。
如果先修过这些相关技术,那么开发中对于代码的理解会更加深刻,而不仅仅是从别人的代码复制过来强行阅读理解,虽然学会了,但本质不一样。
最后感谢在我开发过程中的五月天,周杰伦,林俊杰等,排名不分先后。
感谢自己亲手敲出的上万行代码
?
?
?
?
?
?
?
|