在这个文章里,我会详细的解释JavaWeb其中的一个框架——MVC框架来完成网上教务系统这一个项目。这个项目是使用JDBC去连接数据库,使用了JSP/servlet,在这个文章里我会详细写出一整个项目是如何写出以及思路是怎么样的。这算是比较简单的JavaWeb开发了,适合新手的学习,对有着基础编程能力的人有一定的帮助吧。如果是想要学习更加高阶的可以去学习基于SSM框架(Spring + Spring MVC + Mybatis)或者SSH框架(Spring + Spring MVC + Hibernate)的JavaWeb开发。最后我也是一个写博客小白,希望有什么错误以及思路不对的地方可以私信给予我一下点评,互相进步才是重点。
浏览器端逻辑工具:Javascript(对于前端的讲解会比较少,重点在于思路以及Java代码的编写)
服务器逻辑工具:JSP/Servlet + Java + JDBC
使用到的框架:MVC(后面详细讲)
需求工具:
JDBC连接的jar包:
点击这个颜表情 ❥(^- ^)可以下载到对应的jar包。
Tomcat:
在官网即可下载。配置的话点击这个颜表情❥(^- ^)可以帮助你
在写一个项目的时候,首先不是动手写,而是思考如何去用自己知道的技术去完成。每个人都有自己的想法,而我现在分享一下我的思路和理解。
首先在写之前要了解MVC框架是啥呢?其实这就是一个开发模式,为了使得代码具有健壮性以及可扩展性;每部分有每部分的功能,互相连接着但是逻辑层只能写业务逻辑,控制层只写servlet,视图层只写前端的页面接口,使得每部分的功能完全分开,而不是又在这写一下那写一下,显得毫无章法可言。
而MVC就是Model View Controller的简称。Model指的是模型层;View指的是视图层,泛指渲染页面的JSP;Controller指的是控制器,指的是指向页面的servlet。其中只有MVC够了吗?我觉得还得加上基础编程上需要用到的三层架构以及工具类。
那到底Model模型层有什么用呢?
其实学过封装就知道为什么要独立出这个层去存放了,其实就是封装好bean去存放每个实现方向需要用到的变量,这个按照数据库创建的各个表去建立各个bean即可。比如如果在这个教务系统中我要用到管理员的登录,那就要用到username和password,那数据库存放时还需要自增的id去分别出各个管理员的区别,更好的寻找;那么这一个教务系统的管理员的bean需要的变量是username和password以及一个自增的id。等教务系统管理员登录进去后,就能看到学生的信息,是不是有学生的自增的id、name、sex、bright(出生年月)、email、term(学期)、grate(学年)、phone、以及连接于科目表的subject_id、remark(备注)。name就可以按照写管理员bean一样的,将这些都变成一个变量去存储,然后全部变量就能形成一个学生对象,一个管理员对象…其他的也就像这么写。
那么View层是什么呢?
顾名思义就是页面嘛,给使用者看到的页面,而实现他们是看不到的。比如你去百度一下,百度”我帅不帅”,那么百度一下的那个页面就是我所说的使用者看到的页面,“我帅不帅”的搜索就是你所需要去实现的功能——》搜索功能,但是页面不可能给你看到后端的搜索代码,这就需要使用到JSP/Servlet去实现页面和后端的分离。JSP即是我们的页面,简而言之View层就是编写页面的JSP所构成。
那Controller又是什么呢?
在你写出了页面,也写完了去实现页面的代码,那如何将页面和各自的代码连接起来,以及使用者在使用某个功能的时候会得到想要的结果。这就是Controller解决的问题:导航。将页面和后端代码连接起来的导航。这里面会用到Servlet,后面讲代码的时候会详细讲,现在知道一下就行。
那么说完MVC,三层架构又是什么呢?
三层架构以及MVC最重要的思想就是规范代码,MVC去规范对象——后端——前端。那么在基础编程中编写后端的实现的时候就需要去用到三层架构去规范后端实现代码的编写。在编写后端的时候又分为:Dao层——Service层——Controller层。Dao层就是实现对数据库操作,Service是作为一个连接器一样的东西去连接到Dao层的操作,最后Controller就是使用Service去得到自己想要的实现。这其中一环接一环,层次分明显得代码很规范。那么编写数据库的代码就只能放在Dao层,业务逻辑就放到Service层,而不能突然又把操作数据库的代码写到Service层,把业务逻辑放在Dao层,这是不可以的。
说说工具类:
工具类主要的目的就是简化我们的代码编写,写出一些类共有的方法,在多个类都要用的时候就不用重复的编写,编写出一个工具类,要用到的时候就可以直接调用。这会让我们编写的时候减少很多代码量以及简化代码,而不是代码耦合的现象产生。在教务系统这个项目中,需要用到一个工具类:连接JDBC的工具类。我们系统有管理员、学生、学院、系、课程,里面的Dao层也都要连接数据库,就要使用到JDBC的技术,那么每次连接都要编写一次连接JDBC的操作,这样会增加很多代码,所以写一个连接JDBC的工具类是最好的选择。
那讲完技术的解释,那么现在讲讲思路(只讲写学生操作的思路,其他其实都是差不多的。):
首先,如果对学生操作,是不是先得有学生这个对象呢?那这个对象怎么写呢?在上面讲了,写在bean即可。可以创建一个bean包作为分离,然后在bean包里创建一个java项目:
然后用编译器自带的getter and setter
的生成即可生成对对象的get
操作和set
操作。然后再生成toString
方法(方便用到嘛)。然后最好是写个有参和无参的构造方法放着,等下在数据库获取数据的时候要用到有参构造器去构造学生对象。
其次,我们要想想管理员对学生有什么操作呢?无非就是添加学生的功能,删除学生的功能,修改学生的功能,查询某个学生的功能。老版系统的增删改查都是基本的功能。知道了这个我们在哪里入手呢?那肯定是从后端代码入手对吧,如果是从后端入手,我们就应该先遵从三层架构(在上面我讲了详细的)的编写,那你知道了需要什么功能,那是从Dao层还是Service层还是Controller层入手呢?我建议是先从Service层入手。然后将刚刚的功能转换成代码,但是你只是功能,还未实现那么应该用什么去定义最好呢?那当然就是接口啦,定义一个StudentService的接口类:
那只是接口当然就要去实现它们,那就得写一个类专门去实现它们了,就可以新写一java类去implements它去实现即可:
然后Service去控制Dao层去实现功能,比如上图上的Dao层里的checkAllStudent方法、addStudent方法等等,dao是声明出来的一个StudentDao静态对象,可以使用dao去用它这个对象拥有的方法。按照这个思路我们就得去按照这声明的方法去实现出dao的功能:checkAllStudent、addStudent、deleteStudent、updateStudent、checkStudentById、checkStudentByName
。
直接将方法名复制到dao层即可:
那讲到dao层,是不是应该先连接JDBC呢?所以现在就可以编写一个工具类了:
具体的步骤和方法,在注释里都有写明白了。理解即可。后面的dao要用到JDBC的连接,都可以直接调用这个工具类。
那我们现在来编写dao层:
首先要声明个Connection对象去得到我们工具类的连接:
获取连接以后就可以进行数据库的操作了,首先是checkAllStudent的功能:
PreparedStatement是Statement里的子接口;ResultSet是结果集,用于接收查询以后的结果。
首先要预编译sql语句,再去excuteQuery得到结果集。
获得的结果集可以用getInt、getString、getBoolean…等等的方法去获取值,然后存储到一个变量里,然后将所有的变量用student里的有参构造去传入,然后构造出一个查询出的student对象。因为你不止一个学生,所以用一个list去存储,每次循环得到一个student对象,然后再add进list里,直到rs.next()没有值就跳出循环然后返回list就能将查到的装有student对象的list返回到上一层的serviceImpl里。到此,这个CheckAllStudent就完成了,拿到了想要的,装有student对象的list。这里要记住先,我再讲一个addStudent,等下再接下来讲一下拿到list之后往哪走。addStudent哪里又不一样呢?先上代码
说实话和上面第一个没啥区别,但是多个两个地方:一个是这个要注入参数,还有一个就是executeUpdate和executeQuery以及execute的区别。
那“?”是什么呢?其实它就是个占位符,通俗的比喻说就是这我还有人,你知道就行,你先别管,等下我再告诉你这个人是谁,就是这个意思。在用?占住了位置,然后等下就得告诉机器,这个是谁,那就得用到PreparedStatement对象的setString、setInt、setBoolean…等方法了。第一个参数是位置,第二个参数是值,比如像图中的代码:我第一个?要传入的参数是s_name,s_name是String类型的,所以我就用ps.setString(1 , student.getS_name)
去注入参数。后面的类似,只需要注意一下注入参数的类型,然后用对应的方法去注入参数就可以了。
executeQuery用来查询结果集,一般SELECT类型的sql语句,都会用到它去查询结果集。
executeUpdate用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数,指示受影响的行数(即更新行数)。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。
execute用于执行返回多个结果集、多个更新计数或二者组合的语句。因为多数程序员不会需要该高级功能。execute方法应该仅在语句能返回多个ResultSet对象、多个更新计数或ResultSet对象与更新计数的组合时使用。当执行某个已存储过程或动态执行未知 SQL 字符串(即应用程序程序员在编译时未知)时,有可能出现多个结果的情况,尽管这种情况很少见。 因为方法 execute 处理非常规情况,所以获取其结果需要一些特殊处理并不足为怪。例如,假定已知某个过程返回两个结果集,则在使用方法 execute 执行该过程后,必须调用方法 getResultSet 获得第一个结果集,然后调用适当的 getXXX 方法获取其中的值。要获得第二个结果集,需要先调用 getMoreResults 方法,然后再调用 getResultSet 方法。如果已知某个过程返回两个更新计数,则首先调用方法 getUpdateCount,然后调用 getMoreResults,并再次调用 getUpdateCount。
对于不知道返回内容,则情况更为复杂。如果结果是 ResultSet 对象,则方法 execute 返回 true;如果结果是 Java int,则返回 false。如果返回 int,则意味着结果是更新计数或执行的语句是 DDL 命令。在调用方法 execute 之后要做的第一件事情是调用 getResultSet 或 getUpdateCount。调用方法 getResultSet 可以获得两个或多个 ResultSet 对象中第一个对象;或调用方法getUpdateCount 可以获得两个或多个更新计数中第一个更新计数的内容。
在我们这用executeUpdate就是执行了INSERT语句,影响行数为一行,所以只要执行正确了,行数的变化就是>0,就证明已经执行成功了,就return true,不然就是没有执行或者执行出现错误,就return false。这个只要理解其中的判定即可。然后将得到的true OR false返回到servceImpl里。
然后剩下的删除,更新,按照id查询,按照name模糊查询,都是大同小异,dao里的两种区别比较大的写法我都在这列出来了。用心的人应该很快就可以理解然后把剩下的功能写完。
我解释的两个dao的方法都是得到了想要的数据类型,一个是存储着结果集的list和一个存储着true OR false的boolean类型的数据到达了serviceImpl,那拿到了数据是不是证明要一个导航导航过去页面功能按钮那:我选择了查询全部学生的信息以及我添加了某个学生的信息呢?那如何去实现呢?现在Controller就出来工作了。这个Controller涵盖了MVC里的Controller以及三层架构里的Controller,说明他既能控制三层架构里的serviceimpl,也能控制到JSP。这就完成了导航功能以及前后端断开的实现。比如我现在点击了查询所有学生的信息。那我就得把刚刚查询到的list呈现到前端上然后进行页面的渲染。怎么实现的呢?现在来讲一下servlet和Controller的编写。
首先先创建StudentController
然后继承HttpServlet
:
然后直接打出doGet
和doPost
然后对着他们按alt+/就会出现方法然后就点开即可:
@WebServlet(urlPatterns = {"/CheckAllStudent" , "/AddStudent" ,
"/StudentUpdate" , "/StudentToUpdate" , "/StudentDelete" , "/StudentQueryName"})
然后在类的外面加上这就是在Controller
层里有的方法,这就相当于路标,说明我这有这些方法,各自有自己的方法。(必写)
看了这些代码好像还缺点什么呢?没错就是你拿到uri怎么判断是哪个对应的方法呢?方法怎么去调用呢?这就要在doGet方法里写入这些代码:
路标拿到了,知道自己要去干什么呢,比如我点前端页面的查询全部学生成绩,前端就会传出信息过来我要运行查询学生的/educationsystem/CheckAllStudent
的方法,然后信息get到以后开始进行判定uri是什么,他是/educationsystem/CheckAllStudent
就运行CheckAllStudent(request , response)
方法。
如果点击了添加学生,那么就会运行添加学生的/educationsystem/AddStudent
的方法,然后信息get到以后开始判定uri是什么,他是/educationsystem/AddStudent
就运行AddStudent(request , response)
方法。
到了各自的方法里,肯定是要先声明一个连接前面功能的“按钮”–》serviceImpl,才能拿到前面的功能的方法。
如果你理解了,那么前面ServiceImpl获取到的存储有student对象的list那么我Controller要获取,怎么去获取呢?
就是这句代码:
List<Student> list = studentService.checkAllStudent();
那么拿到了需要的信息list,那怎么传到页面上呢?这就是Servlet和JSP自己的数据交换的协议了,我们可以将获取的数据存储在一个缓存Session里,然后需要用到的时候就可以给JSP自己拿到。
就可以 用到这个语句:
request.getSession().setAttribute("StudentList" , list);
然后再用setAttribute将数据存储在缓存,表单控件中的Object的 name与value是存放在一个哈希表中的,然后在这里给出Object的name会到哈希表中找出对应它的value。
存储好数据后,再重定向一下页面。
request.getRequestDispatcher("StudentTables.jsp").forward(request, response);
在JSP里自然有自己的获取信息的办法,现在JSP如何去获取呢?
这个就是上面重定向的StudentTables.jsp
页面获取信息的方式,我解释一下,刚刚是将list存储在缓存里,怎么存储的?name
就是StudentList
,value就是list,那在JSP获取信息的时候就是用遍历的方法去遍历你存储在StudentList里的数据,然后将数据分别用前端的编码的方式显示在页面上。这是JSP/Servlet的数据交换方式。在我学习基础编程的时候,我最头疼的就是数据交换方式,还得要自己去编写TCP数据协议。但是在这里就很简单很明了。这就是JSP/Servlet连接的方式。
添加数据又和查询反了一个操作方向,查询是从数据库查询出数据然后再返回到页面,而添加数据是从页面传入数据,然后将数据再传到数据库进行存储。
那就要用到request.getParameter()
这个方法了,这个方法是从JSP中获取数据,获取的数据只能用String来接收。那这么一说,添加数据也不难了。
String s_name = request.getParameter("s_name");
String s_sex = request.getParameter("s_sex");
String s_bright = request.getParameter("s_bright");
String s_email = request.getParameter("s_email");
String term = request.getParameter("s_term");
int s_term = Integer.parseInt(term);
String grate = request.getParameter("s_grate");
int s_grate = Integer.parseInt(grate);
String s_phone = request.getParameter("s_phone");
String id = request.getParameter("su_id");
int su_id = Integer.parseInt(id);
String s_remark = request.getParameter("s_remark");
Student student = new Student();
student.setS_name(s_name);
student.setS_sex(s_sex);
student.setS_bright(s_bright);
student.setS_email(s_email);
student.setS_term(s_term);
student.setS_grate(s_grate);
student.setS_phone(s_phone);
student.setSu_id(su_id);
student.setS_remark(s_remark);
这一段都是从JSP中获取的数据,然后将数据存储到student对象里,然后再将这个对象传入studentService
的addStudent()
方法里。
boolean isOk = studentService.addStudent(student);
利用返回值去进行页面的重定向:
if(isOk) {
request.getRequestDispatcher("/CheckAllStudent").forward(request, response);
}else {
request.getRequestDispatcher("/addStudent.jsp").forward(request, response);;
}
对于JSP/Servlet其实很简单,就是获取到的数据存储到缓存了,然后JSP通过存到缓存时建立的哈希表的name进行获取,然后遍历,就能获取到数据然后显示到页面上。然后如果是页面存储数据到数据库,就用getParameter
去获取信息然后进行操作,然后通过返回的boolean进行判断,然后进行页面的重定向即可。
其实JSP和HTML的编写很相似,只是多了它里面可以进行逻辑的判断和操作,比HTML更加的灵活,所以动态页面的编写都不只是单纯的HTML和JS的编写,更多的是jsp、aspx、asp、jsp、php、perl、cgi去编写。我对于前端的编写也不是太在行,所以也不在这献丑了,我只是想分享一下我写JavaWeb的新路历程。当然教务系统肯定不止这些功能,但是我觉得都是大同小异,只要你用心的看一下我讲的,再下定决心去打一下代码。我相信你能完成我剩下没说的学生功能以及管理员登录,学院管理,课程管理,专业管理。学习总是困难的,只是在学完过后有一种豁然开朗的感觉,才是一个人学习的最让人羡慕的地方吧。在对于JavaWeb基础编程的学习,也是刚起步,往后就开始学习SSM+mybetis+redis了。更加需要自己的鼓励以及努力,我也是个编程菜鸟,希望各位大牛不要太在意,或者能指点一下更加的好,我会虚心学习;而对于刚入门的小白,我觉得我这篇文章对于思路的讲解还是很完整的,希望对你有所帮助。
百度网盘:https://pan.baidu.com/s/1fbhnAkwWjvjouelYoZoRhA
提取码:4keb