目录
引言:在此说明在本次课设过程中所遇到的困难!
一、项目搭建的问题
Q1:Web项目应用啥么编译器编写?
Q2:如何创建Web项目(MAVEN)?
Q3:Tomcat服务器开头控制台显示乱码如何解决?
Q4:Tomcat服务器怎么设置项目的开始界面,从而只要在输入项目名便可访问项目?
Q5:Tomcat服务器的资源映射设置问题?
二、前端编程遇到的相关问题
Q1.如何完成前端界面的搭建?
Q2:如何完成前端日历和实时时间显示功能的实现?
Q3:如何完成前端待办的添加删除和倒计时操作?
Q4:如何完成前端折线图的展示操作?
三、前后端交互时遇见的问题
Q1:后端如何获得前端的请求并处理?
Q2:如何将后端的数据打印到前端界面上?
Q3:如何在一个用户切换前端界面时候,在不同界面记住用户的账号,从而以此访问数据库?
Q4:前端如何将数据存入数据库?
引言:在此说明在本次课设过程中所遇到的困难!
一、项目搭建的问题
Q1:Web项目应用啥么编译器编写?
刚开始接触时,我了解到编web的项目需要一个Web项目的工程结构,而由于平常打Java代码接触最多的便是vscode因为它有非常多的插件,且它进行前端编写也十分方便,所以vscode便成为了我的首要之选。
Q2:如何创建Web项目(MAVEN)?
参考资料:VsCode配置JavaWeb(最新)-CSDN博客
通过该博客我了解到vscode可以引入MAVEN,进行web项目模板的自动创建,于是我便开始MAVEN的配置和下载。
1.安装好MAVEN
2.vscode的MAVEN配置
3. 创建MAVEN项目,因为MAVEN生成的项目结构还少了点东西需要我们自己补上。
这样创建的结构则为MVC的开发模式,将前端、后端代码分开编程,便于维护。
项目结构图:
Q3:Tomcat服务器开头控制台显示乱码如何解决?
Tomcat作为Servlet类的实现者,其重要性不言而喻,开始安装Tomcat时,发现控制全是乱码,后面查询信息了解到是编码问题。
给日志文件加中文编码GDK
Q4:Tomcat服务器怎么设置项目的开始界面,从而只要在输入项目名便可访问项目?
通过学习了解到只要配置web.xml文件,给它添加欢迎文件即可!
Q5:Tomcat服务器的资源映射设置问题?
这也是令我最头疼的问题,上传到tomcat的web界面老是显示不出css加载和音乐相关背景图片等资源,后面才发现是tomcat的解析url与本地浏览器不同,地址需要添加映射。
解决方法:
在tomcat的server.xml的配置文件里配置资源文件访问的路径,tomcat会将url的尾部字符与其匹配,相配则访问该路径的资源文件,这里使用了绝对路径,因为不知道为什么,相对路径老是访问失败,就没成功过!
添加Context标签,来做地址映射
二、前端编程遇到的相关问题
Q1.如何完成前端界面的搭建?
前端界面主要用了原生的HTML5、CSS进行搭建各功能的组件容器,div标签进行了页面布局CSS进行美化,使得JS更容易调用相应组件。
Q2:如何完成前端日历和实时时间显示功能的实现?
前端日历功能所需要两个按钮,主要靠JS实现,JS访问日历模块容器的标签,其本质可看作一个数组,然后通过JS创建各个标签,并推入标签容器,再通过CSS实现排版便可以展示。而按钮只要改变月份变量,复用创造日历的函数导入改变后的月份参数即可通过刷新月份显示不同月的月份。以下是具体实现代码:
function showMouth(){//日历模块中间显示年月
document.getElementById("date").innerHTML="";
var yearandmouth=year+"年"+Month+"月";
document.getElementById("date").innerHTML=yearandmouth;
}
function getMonthDay(monthnumber){//获得每月多少天
var fullMonthDay=0;
if(monthnumber==2){
if(year%400==0||(year%100!=0&&year%4==0)){
fullMonthDay=29;
}else fullMonthDay=28;
} else if(monthnumber==4||monthnumber==6||monthnumber==9||monthnumber==11){
fullMonthDay=30;
} else fullMonthDay=31;
return fullMonthDay;
}
function showDay(firstday){//添加日历的每一个日
document.getElementById("day").innerHTML="";
var fullMonthDay=0;
var weekday=firstday.getDay();//获取星期几!
var days=document.getElementById("day");
fullMonthDay=getMonthDay(Month);
for(var i=1;i<weekday;i++){
var dayElement= document.createElement("div");
dayElement.innerHTML=" ";
dayElement.className="everyday";
days.appendChild(dayElement);
}//前面的空格
for(var i=1;i<=fullMonthDay;i++){
var dayElement=document.createElement("div");
dayElement.className="everyday";
dayElement.innerHTML=i;
if(i==day&&Month==month){
dayElement.style.color="blue";
}
days.appendChild(dayElement);
}
}
function up(){//按钮加一个月
Month=(Month+1)%12;
if(Month==0)Month=12;
var firstday=new Date(year,Month-1,1);//给定日期创建对象
showDay(firstday);
showMouth();
}
function down(){//按钮减少一个月
Month=(Month-1)%12;
if(Month==0)Month=12;
var firstday=new Date(year,Month-1,1);//给定日期创建对象
showDay(firstday);
showMouth();
}
function Calendar(){//打包封装
showMouth();
var firstday=new Date(year,Month-1,1);//给定日期创建对象
showDay(firstday);
};
Q3:如何完成前端待办的添加删除和倒计时操作?
与日历模块的建造方式异曲同工,也是通过获取用户输入的数据,然后建立一个父标签,再创建各个子标签,对子标签的赋值,然后将子标签推入父标签。从而完成一个待办的建立。通过按钮调用倒计时功能,倒计时通过建立一个预设时间,让即使时间减去预设时间实现时间的倒数。
下面是具体的实现代码:
待办创建和倒计时功能:
function add(){//添加待办按钮函数
var flag=0;
var toDo;
var countHour;
var countMin;
toDo=prompt("请输入要添加的待办项!");
if(!toDo){
alert("您输入的内容为空,请重新添加!")
}else{
countHour=prompt("请输入持续时间,单位:小时");
if(countHour.indexOf(".")==-1){
countHour=parseInt(countHour);
if(countHour!=null&&countHour>=0&&countHour<=24){
countMin=prompt("请输入持续时间,单位:分钟");
if(countMin.indexOf(".")==-1){
countMin=parseInt(countMin);
if(countMin!=null&&countMin>=0&&countMin<=60){
alert("添加成功!");
flag=1;
}else{
alert("输入数据非法,请重新添加!")
}
}else{
alert("小时:请输入整数!");
}
}else{
alert("输入数据非法,请重新添加!")
}
}else{
alert("分钟:请输入整数!");
}
}
if(flag){
addDeal(toDo,countHour,countMin);
}
}
function addDeal(toDo,countHour,countMin){//添加待办具体实现
var schedule=document.getElementById("schedule");
if(schedule.getElementsByTagName("div").length==0){
schedule.innerHTML=""
}
var row=document.createElement("div");
var checkbox=createcheckbox();
var text=createctext(toDo);
var countdown=createcountdown(countHour,countMin);
var starts=createstarts();
row.append(checkbox,text,countdown,starts);
schedule.appendChild(row);
}
function createcheckbox(){//创建勾选框
var checkbox=document.createElement("input");
checkbox.className="checkbox";
checkbox.type="checkbox";
checkbox.onclick=function(){
if(checkbox.checked==true){
alert("恭喜完成本次任务!");
updateline();
var parent= checkbox.parentElement;
Current=parent;
deleteToDoDeal();
}
}
return checkbox;
}
function createctext(toDo){//创建待办文本
var text=document.createElement("span");
text.className="text";
text.innerHTML=toDo;
return text;
}
function createcountdown(countHour,countMin){//创建计时器显示
var countdown=document.createElement("input");
countdown.className="countdown";
countdown.type="time";
countHour=countHour<10?"0"+countHour:countHour;
countMin=countMin<10?"0"+countMin:countMin;
countdown.value=countHour+":"+countMin;
countdown.disabled=true;
return countdown;
}
function createstarts(){//创建开始计时按钮
var starts=document.createElement("button");
starts.className="starts";
starts.onclick=function(){
clearInterval(breakout);
var parent=starts.parentElement;
Current=parent;
var time=parent.getElementsByClassName("countdown");
var value=time[0].value;
var hh=parseInt(value.substring(0,2));
var mm=parseInt(value.substring(3,5));
var ss=0;
setpreTime(hh,mm,ss);
breakout=setInterval(countdownTime,500);
}
return starts;
}
function deleteToDo(){//删除待办
var num=prompt("请输入要删除的待办序号!");
var node=schedule.childNodes
if(num&&num.indexOf(".")==-1){
num=parseInt(num);
if(num>0&&num<=schedule.getElementsByTagName("div").length){
Current=node[num-1];
deleteToDoDeal();
}else{
alert("未找到该条待办!");
}
}else{
alert("未输入整数或输入序号为空!");
}
}
function deleteToDoDeal(){//删除主操作
var schedule=document.getElementById("schedule");
schedule.removeChild(Current);
clearInterval(breakout);
var elem =document.getElementById("countdowntext");
elem.innerHTML="";
if(schedule.getElementsByTagName("div").length==0){
var maintest=document.createElement("p");
maintest.id="maintest";
maintest.className="maintext";
maintest.textContent="无待办内容!"
schedule.appendChild(maintest);
}
}
function setpreTime(hh,mm,ss){//预设时间
preTime=new Date();
preTime.setHours(preTime.getHours() + hh);
preTime.setMinutes(preTime.getMinutes() + mm);
preTime.setSeconds(preTime.getSeconds() + ss);
}
function countdownTime(){//倒计时主操作
if(!preTime) return false; // 如果未设置预设时间,返回
var date = new Date(); // 获取当前时间
var time = preTime - date; // 计算时间差
time =time/1000;
if(time<=0){
preTime=0;
if(preTime==0){
alert("恭喜完成本次任务!");
deleteToDoDeal();
updateline();
}
return true;
}
var h = time >= 3600 ? parseInt(time / 3600) : 0; // 计算小时
var m = time >= 60 ? parseInt((time - h * 3600) / 60) : 0; // 计算分钟
var s = parseInt(time - h * 3600 - m * 60); // 计算秒
h=h<10?"0"+h:h;
m=m<10?"0"+m:m;
s=s<10?"0"+s:s;
var elem=document.getElementById("countdowntext");
elem.innerHTML=h+":"+m+":"+s;
}
其中倒计时用到反复调用函数,但有时候需要打断计时,此时则需要设定一个全局变量来作为打断它函数的参数。
Q4:如何完成前端折线图的展示操作?
为了提高效率,折现图开始想用css画,后面发现不是很成功,于是查资料了解到ECHARTS技术,设置其配置文件给其添加数据即可画出相当漂亮的折线图。以下是实现代码:
function updateline(){
addcnt();
line();
}
function getX(){//获取当月
var fullMonthDay=getMonthDay(month);
var data=[];
for(var i=1;i<=fullMonthDay;i++){
str=month.toString()+"/"+i.toString();
data.push(str);
}
return data;
}
function init(){//初始化专注次数数组
var fullMonthDay=getMonthDay(month);
for(var i=1;i<=fullMonthDay;i++){
datacnt.push(0);
}
}
function addcnt(){//更新专注次数数组
datacnt[day-1]++;
}
function line(){//具体配置代码
var dataY=datacnt;
var dataX=getX();
//3.初始化实例对象 echarts.init(dom容器)
var myChart = echarts.init(document.getElementById("linechart"));
//4.指定配置项和数据
var option = {
title: {
text: '月专注记录',
textStyle:{
color:'white'
}
},
tooltip: {},//
legend: {//图例组件
data:['专注次数'],
textStyle:{
fontSize:16,
color: "#ffffff"
}
},
xAxis: {
data: dataX,
},
yAxis: {
type:'value'
},
dataZoom: [
{
type: 'slider', // 滑动条
show: true, // 显示滑动条
// zoomLock: true,//设置滑栏不可调缩放
xAxisIndex:[0],
start: 0, // 滑动条开始位置
end: 100, // 滑动条结束位置
}
],
series: [{
data: dataY,
name: '专注次数',
type: 'line',
}]
};
//5.将配置项设置给echarts实例对象,使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
};
//折线图实现
其中需要一个数组作为全局变量同时也作为月专注记录的存储,这样方便结束一次待办时,更新折线图。
三、前后端交互时遇见的问题
Q1:后端如何获得前端的请求并处理?
通过编写Servlet继承HttpServlet,覆写doGet和doPost方法。doPost方法用于处理Post请求,如登录界面的表单提交,xml发起的post请求等。doGet方法用于加载数据,处理前端发送的GET请求。其中最要注意的是请求需要绑定servlet,这里采用了Servlet注释配置的方法。绑定servlet是要求tomcat能找到相关servlet类的具体位置,再把它加载进内存。
Servlet注释配置
@WebServlet(name = "LoginServlet",urlPatterns = "/Login")
加载和存储专注数据代码
package com.example.servlet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.example.dao.UserMessage;
import com.example.model.User;
@WebServlet(name = "RequestUserMessageCntServlet",urlPatterns = "/RequestUserMessageCnt")
public class RequestUserMessageCntServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("开始加载数据折线图数据!");
HttpSession session= request.getSession();
String username=(String) session.getAttribute("username");
UserMessage userMessage=new UserMessage();
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
User user = userMessage.loadUserMessage(username);
ArrayList<Integer> arrayList=user.getCnt();
for (Integer integer : arrayList) {
response.getWriter().write(Integer.toString(integer)+" ");
}
System.out.println("折线图数据,加载完毕!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
String line=null;
ArrayList<Integer> cnt=new ArrayList<>();
while((line= reader.readLine())!=null){
cnt.add(Integer.parseInt(line));
}
HttpSession session= request.getSession();
String username=(String) session.getAttribute("username");
UserMessage userMessage=new UserMessage();
userMessage.saveUserMessageCnt(username, cnt);
}
}
登录处理操作代码
package com.example.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.example.utils.JDBCUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@WebServlet(name = "LoginServlet",urlPatterns = "/Login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//处理客户端的post请求
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//解决乱码问题!设置内容都为utf-8格式
PrintWriter out = response.getWriter();
String username = request.getParameter("name");
String password = request.getParameter("secret");
HttpSession session=request.getSession();
//创建一个会话对象!
JDBCUtils.registerDriver();
Connection connection=JDBCUtils.getConnection();
PreparedStatement pStatement=null;
try {
ResultSet resultSet=JDBCUtils.checkExit(username, pStatement, connection);
if(resultSet.next()){
if(!password.equals(resultSet.getString("password"))){
out.write("<script language='javascript'>alert('密码错误,请重新输入!');window.location.href='/Todoproject/login.html'</script>");
}else{
session.setAttribute("username", username);
out.write("<script language='javascript'>alert('登录成功!');window.location.href='/Todoproject/menu.html'</script>");
}
}else{
//如果没有找到!
out.write("<script language='javascript'>alert('该用户不存在!');window.location.href='/Todoproject/login.html'</script>");
}
} catch (SQLException e) {
e.printStackTrace();
out.write("<script language='javascript'>alert('系统发生错误!');window.location.href='/Todoproject/login.html'</script>");
}finally{
JDBCUtils.closeConnection(connection);
}
}
}
待办数据载入和存储代码
package com.example.servlet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.example.dao.UserMessage;
import com.example.model.ToDoList;
import com.example.model.User;
@WebServlet(name = "RequestUserMessageToDoServlet",urlPatterns = "/RequestUserMessageToDo")
public class RequestUserMessageToDoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("开始加载待办数据!");
HttpSession session= request.getSession();
String username=(String) session.getAttribute("username");
UserMessage userMessage=new UserMessage();
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
User user = userMessage.loadUserMessage(username);
ArrayList<ToDoList> doLists=user.getLists();
for(int i=0;i<doLists.size();i++){
String toDo=doLists.get(i).getToDo();
String countHour=doLists.get(i).getTime().substring(0, 2);
String countMin=doLists.get(i).getTime().substring(3,5);
response.getWriter().write(toDo+" "+countHour+" "+countMin+" ");
}
System.out.println("待办数据加载成功!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedReader reader=new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8"));
HttpSession session= request.getSession();
String username=(String) session.getAttribute("username");
String line=null;
ArrayList<ToDoList>toDos=new ArrayList<>();
while((line=reader.readLine()) != null){
String []strs=line.split(" ");
ToDoList toDoList=new ToDoList(strs[0], strs[1]);
toDos.add(toDoList);
}
UserMessage userMessage=new UserMessage();
userMessage.saveUserMessageToDo(username, toDos);
}
}
加载用户登录名
package com.example.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet(name = "RequestUserNameServlet",urlPatterns = "/RequestUserName")
public class RequestUserNameServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session= request.getSession();
String username=(String) session.getAttribute("username");
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(username);
System.out.println(username+"用户已成功连接!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
Q2:如何将后端的数据打印到前端界面上?
一种方法是调用PrintWriter对象的write方法给前端发送js语句从而弹出提示窗口。另一种方法是传递数据到前端的js,js通过xml接收并处理数据再赋值给对应模块,展示在web页面上。
以下是相关代码:
第一种:
PrintWriter out = response.getWriter();
out.write("<script language='javascript'>alert('密码错误,请重新输入!');window.location.href='/Todoproject/login.html'</script>");
第二种:
response.getWriter().write(Integer.toString(integer)+" ");
//用空格作分界符,方便js处理数据
xml处理
var arr=xml.responseText.split(" ");
为什么需要空格呢?因为后端传来的数据是一个全部数值挤在一起的字符串,需要通过空格作为分界符号。同理前端传来的代码也一样。
Q3:如何在一个用户切换前端界面时候,在不同界面记住用户的账号,从而以此访问数据库?
用到了session会话来记录用户的用户名,用会话保存的数据可以被多次访问,从而实现跨界面的传递,以此通过用户名访问数据库。
保存用户名
读取用户名
Q4:前端如何将数据存入数据库?
前端通过js的xml的send()发送数据一定要指定分界符,要不然传输到后端数据会难以处理,数据传到后端后再通过Dao模式使用相关数据库指令存入数据库。
xml相关代码:
function saveUserMessageCnt(){//保存专注次数记录
var str=null;
var xml = new XMLHttpRequest();
xml.onreadystatechange = function() {
if (xml.readyState === XMLHttpRequest.DONE) {
if (xml.status === 200) {
console.info('专注记录保存成功!');
} else {
console.error('专注记录保存失败!');
}
}
};
xml.open('POST','http://localhost:8080/Time/RequestUserMessageCnt',true);
xml.setRequestHeader('Content-Type', 'text/plain'); // 设置请求头为纯文本格式
for(var i=0;i<datacnt.length;i++){
if(str==null)str=(datacnt[i].toString()+"\n");
else str=str+(datacnt[i].toString()+"\n");
}
console.info(str);
xml.send(str);
}
这里采用空格作为分界符,通过send函数发送到后端。
后端处理代码:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedReader reader = new BufferedReader(new
InputStreamReader(request.getInputStream(), "UTF-8"));
String line=null;
ArrayList<Integer> cnt=new ArrayList<>();
while((line= reader.readLine())!=null){
cnt.add(Integer.parseInt(line));
}
HttpSession session= request.getSession();
String username=(String) session.getAttribute("username");
UserMessage userMessage=new UserMessage();
userMessage.saveUserMessageCnt(username, cnt);
}
此处的userMessage为Dao模式的接口实现类,实现了数据库的存取操作。