大家好,又见面了,我是你们的朋友全栈君。
转载请注明出处:https://blog.csdn.net/binbinqq86/article/details/81746294
项目简介
本文是笔者自己学习后台开发打响的第一枪,也是后台开发最基础的了,记得刚毕业的时候做过一个web项目,一直到今天都没有再了解过这方面,如今重新拾起,感觉还是需要多了解一些后端的东西,如果一直停留在移动端和前端,知识面未必太过狭窄。这次主要就是做了一个简易版的用户登录注册管理系统,实现了基本的增删查改,当然还有很多不完善的地方,后续随着学习的深入再去逐渐深入和完善。
环境搭建
本项目开发的环境为Mac10.12.6系统,jdk选择的是1.8
ide的选择
ide的话,由于我之前开发Android用的是eclipse,知道它也可以做web项目,不过后来谷歌推出Android Studio后,eclipse就立刻被鄙视下去了,jetBrains公司所推出的IntelliJ IDEA(以下简称idea),在智能代码助手、代码自动提示、重构、J2EE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的,可以说你用过之后,就不想再回到eclipse时代了,不过如果你还是喜欢用eclipse,两者的项目也是可以相互转换的,它的旗舰版本还支持HTML,CSS,PHP,MySQL,Python等。免费版只支持Java等少数语言。该公司还推出了PyCharm、DataGrip、PhpStorm、WebStorm等众多ide工具,可以说非常好用和强大。下载地址如下:https://www.jetbrains.com/idea/download/
版本的话,这里要注意一下,我们选择红框的这个版本,它包含的功能更全面,右边的是免费版,但是功能有限,不能去部署tomcat服务器。
数据库相关
数据库这里我们就选择mysql8.0.12社区版本,官网下载地址如下:https://dev.mysql.com/downloads/mysql/
我们选择dmg安装版本即可。安装完成之后会在设置里面生成快捷键,可以进去启动和停止mysql服务:
当然也可以通过命令行去启动,这里我们把mysql配置到环境变量里面去,这样方便一些,打开/etc/profile文件,在里面添加如下一行即可:
export PATH=$PATH:/usr/local/mysql-8.0.12-macos10.13-x86_64/bin
启动服务就可以不用进到bin目录下再输入命令了,每个平台的命令不一样,这里不再赘述。当然你也可以用其他查看数据库的软件比如navicat premium,datagrip,idea自带的database来建立和查看数据库,不过最好建议用命令行的方式去操作这些,过度依赖ide,不是一个好的习惯,毕竟后面数据库crud操作都是sql语句,包括建表什么的,所以说还是用命令比较好,这里推荐去w3school看看基本的教程就可以了,后面可以在学习的过程中慢慢去熟练。
tomcat相关
tomcat就是用来部署我们的web程序的容器,我们的项目可以在里面去跑,说白了就是服务器。我们去官网下载即可,这里我选择的是8.0版本,下载地址如下:https://tomcat.apache.org/download-80.cgi
我们选择如下红框内的去下载:
下载后直接解压即可,无需安装,然后配置到环境变量:
export PATH=$PATH:/Users/tb/Library/apache-tomcat-8.0.53/bin
然后打开终端,运行startup.sh即可打开tomcat服务,在浏览器输入http://localhost:8080即可打开tomcat首页,代表已经成功了。如需更改端口号,打开config目录下的server.xml配置即可,另外我们需要添加一个默认用户,同样打开config目录下,找到tomcat-users.xml文件,添加如下即可:
<role rolename="manager-gui"/>
<user username="admin" password="admin" roles="manager-gui"/>
然后重启服务,我们就可以用admin登录了。
开始
上述都是基本的准备工作,下面我们就可以开始真正的编码了,打开idea,新建工程:
然后下一步选择工程目录和项目名称,完成即可。项目目录结构如下:
接下来我们在web.xml里面添加如下:
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
这个就代表我们的首页了,接下来我们配置一下服务器:
我们选取这里的Edit Configurations…,打开窗口:
注意:如果这里看不到tomcat选项,一个原因就是开头说的idea版本问题,另外就是需要安装一个插件:
我们点击Local后,配置如下:
Deployment标签中配置如下:
配置完成后,我们点击右上角的绿色三角形运行按钮,启动服务器,可以在这里查看日志:
然后,我们启动浏览器输入http://localhost:8090,就可以看到我们的首页了:
JDBC封装
上面我们已经部署好服务器,并且可以运行我们的程序了,下面我们就开始真正的编码业务,首先就是数据库这块了,我们的源码目录结构如下:
JdbcUtil就是我们封装的数据库工具类:
/** * @author tb * @time 2018/8/14 下午5:07 * @des 获取数据库连接对象 */
public class JdbcUtil {
//mysql驱动包名
private static final String DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
//数据库名称
private static final String DB_NAME = "tb";
//数据库连接地址
private static final String URL = "jdbc:mysql://localhost:3306/" + DB_NAME + "?characterEncoding=utf8&useSSL=false&serverTimezone=GMT";
//用户名
private static final String USER_NAME = "root";
//密码
private static final String PASSWORD = "tb123=root";
/** * @return */
public static Connection getConnection() {
Connection connection = null;
try {
Class.forName(DRIVER_NAME);//注意要把jdbc的jar包放到tomcat的lib目录下
connection = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
if(connection!=null){
System.out.println("connection to the database is success......");
}else{
System.out.println("connection to the database is failure......");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
}
这里有个注释,就是我们项目里面首先需要引入mysql提供的jdbc的jar包,官网下载地址如下:https://dev.mysql.com/downloads/connector/j/5.0.html
下载之后,得到一个jar包,放到工程的lib目录下,然后加入引用即可,另外我们需要放一份到我们的tomcat的lib目录下,否则后面在网页上调用servlet的时候,操作数据库tomcat会找不到jdbc的驱动类。
DAO封装
dao就是用来操作数据库的一个对象,我们做如下封装:
/** * @author tb * @time 2018/8/14 下午5:02 * @des 所有crud的抽象 */
public interface IDao<T> {
/** * 向数据库增加n条数据 * * @param list 需要插入的数据集合 * @return 返回受影响的条数 */
int[] create(List<T> list);
/** * 向数据库查询数据 * * @param o 需要查询的条件 * @return 返回查到的数据集合 */
List<T> read(Object o);
/** * 向数据库更新数据 * * @param list 需要更新的数据集合 * @return 返回受影响的条数 */
int[] update(List<T> list);
/** * 向数据库删除数据 * * @param list 需要删除数据的条件集合 * @return 返回受影响的条数 */
int[] delete(List<Object> list);
}
写一个抽象接口,这样不同的对象都可以使用,下面是具体实现,
/** * @author tb * @time 2018/8/14 下午5:08 * @des 用户操作相关 */
public class UserDaoImpl implements IDao<User> {
private Connection connection;
private PreparedStatement preparedStatement;
public static UserDaoImpl getInstance() {
return SingletonInstance.instance;
}
private static class SingletonInstance {
private static final UserDaoImpl instance = new UserDaoImpl();
}
private UserDaoImpl() {
connection = JdbcUtil.getConnection();
String sql = "create table if not exists user" +
"(userId int(10) auto_increment primary key," +
"userName varchar(20) not null," +
"nickName varchar(20) null," +
"password varchar(20) not null," +
"role int(5) default '0' not null," +
"constraint userName unique (userName)" +
") DEFAULT CHARSET=utf8mb4";//支持emoji表情
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute();
} catch (SQLException e) {
e.printStackTrace();
} finally {
CloseUtil.closeQuietly(connection, preparedStatement);
}
List<User> list=read(null);
if(list!=null&&list.size()>0){
for (User u:list) {
if(u.userName.equals("admin")){
return;
}
}
}
//添加一个默认的管理员
List<User> l=new ArrayList<>();
User u=new User();
u.userName="admin";
u.nickName="admin";
u.role=-1;
u.password="admin";
l.add(u);
create(l);
}
@Override
public int[] create(List<User> list) {
String sql = "insert into user(userName,nickName,password,role) values(?,?,?,?)";
try {
if (connection == null || connection.isClosed()) {
connection = JdbcUtil.getConnection();
}
preparedStatement = connection.prepareStatement(sql);
for (User user : list) {
preparedStatement.setString(1, user.userName);
preparedStatement.setString(2, user.nickName);
preparedStatement.setString(3, user.password);
preparedStatement.setInt(4, user.role);
preparedStatement.addBatch();
}
return preparedStatement.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
} finally {
CloseUtil.closeQuietly(connection, preparedStatement);
}
return null;
}
@Override
public List<User> read(Object o) {
List<User> list = new ArrayList<>();
ResultSet resultSet;
String sql = "select * from user where userName=?";
if (o == null) {
sql = "select * from user";
}
try {
if (connection == null || connection.isClosed()) {
connection = JdbcUtil.getConnection();
}
preparedStatement = connection.prepareStatement(sql);
if (o != null) {
preparedStatement.setString(1, String.valueOf(o));
}
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
User user = new User();
user.userName = resultSet.getString("userName");
user.nickName = resultSet.getString("nickName");
user.password = resultSet.getString("password");
user.userId = resultSet.getInt("userId");
user.role = resultSet.getInt("role");
list.add(user);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
} finally {
CloseUtil.closeQuietly(connection, preparedStatement);
}
return null;
}
@Override
public int[] update(List<User> list) {
String sql = "update user set nickName=?,password=?,role=? where userName=?";
try {
if (connection == null || connection.isClosed()) {
connection = JdbcUtil.getConnection();
}
preparedStatement = connection.prepareStatement(sql);
for (User user : list) {
preparedStatement.setString(1, user.nickName);
preparedStatement.setString(2, user.password);
preparedStatement.setInt(3, user.role);
preparedStatement.setString(4, user.userName);
preparedStatement.addBatch();
}
return preparedStatement.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
} finally {
CloseUtil.closeQuietly(connection, preparedStatement);
}
return null;
}
@Override
public int[] delete(List<Object> list) {
String sql = "delete from user where userName=?";
try {
if (connection == null || connection.isClosed()) {
connection = JdbcUtil.getConnection();
}
preparedStatement = connection.prepareStatement(sql);
for (Object o : list) {
preparedStatement.setString(1, String.valueOf(o));
preparedStatement.addBatch();
}
return preparedStatement.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
} finally {
CloseUtil.closeQuietly(connection, preparedStatement);
}
return null;
}
}
我们采用懒汉式的静态内部类单例,构造函数里面去对数据库的user表来一个初始化,并添加一个默认的admin用户,我们来查询一下,看看表结构:
这里我们的数据库和表都采用utf8mb4编码格式,可以用来支持中文和emoji表情。crud我们均采用preparedStatement来防止sql注入,提高效率。
Junit编写
crud都写好了,下面就来编写测试用例来验证一下,我们需要引入juint的插件,然后新建一个test文件夹,右键选择Make Directory As/Test Resource Root,把它转化为源码测试目录,可以看到颜色就会改变,然后在需要测试的类名上按下Alt+enter键,选择create test,
选择需要测试的方法,就会自动为我们创建如下目录和测试类:
接下来我们直接写测试代码即可:
public class UserDaoImplTest {
private UserDaoImpl userDao = UserDaoImpl.getInstance();
private List<User> list = new ArrayList<>();
@Before
public void init() {
list.clear();
User user1 = new User();
user1.password = "1";
user1.userName = "user1";
list.add(user1);
User user2 = new User();
user2.password = "2";
user2.userName = "user2";
list.add(user2);
User user3 = new User();
user3.password = "3";
user3.userName = "user3";
list.add(user3);
}
@Test
public void create() {
int[] res=userDao.create(list);
assertEquals(3,res.length);
}
@Test
public void read() {
List<User> l=userDao.read("user1");
assertEquals(1,l.size());
assertEquals("user1",l.get(0).userName);
}
@Test
public void update() {
List<User> l=userDao.read("user1");
l.get(0).nickName="haha";
int[] i=userDao.update(l);
assertEquals(1,i.length);
}
@Test
public void delete() {
List<Object> l=new ArrayList<>();
l.add("user3");
l.add("user2");
int[] i=userDao.delete(l);
assertEquals(2,i.length);
}
}
需要测试哪个方法,点击下图红圈的按钮即可,测试通过就代表没问题,不然就要重新检查代码了
jsp编写
下面开始编写我们的页面:
这里我们统一放到user文件夹下面方便管理,分别对应登录,修改,增加注册页面,首页我们放在了外边,具体代码就不在这里贴出了,都是基本的js和html,感兴趣的可以去下载源码查看(文章最后会给出源码)。
servlet编写
有了页面,就需要去跟数据库交互了,这里就用到了servlet(当然也可以在jsp页面中操作数据库,但这么做不好),他就是负责数据库跟页面之间交互的,就是mvp模式中的p。我们以登录为例:
/** * @author tb * @time 2018/8/15 下午4:46 * @des 用户登录 */
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//必须注释掉,里面已经resp.sendError了
// super.doPost(req, resp);
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");//写入数据库防止乱码
//此处对应JSP中的标签名,必须是name属性
String userName = req.getParameter("userName");
String password = req.getParameter("password");
List<User> list = UserDaoImpl.getInstance().read(userName);
if (list != null && list.size() > 0 && password.equals(list.get(0).password)) {
System.out.println("登录成功==="+list.get(0).toString());
//登录成功后,就将用户存储到session中
//登陆成功,我是重定向到其它页面,重定向request作用域不能延伸
//所以这里我要用session才可以把成功的信息传递给index.jsp
req.getSession().setAttribute("user", list.get(0));
req.getSession().setAttribute("welcome", userName);
resp.sendRedirect("index.jsp");
} else {
System.out.println("=========登录失败========");
//登陆失败,我用的是转发,转发request作用域是连续的,所以我这里可以用request传递失败的信息给jsp页面
req.setAttribute("msg", userName + "登录失败");
req.getRequestDispatcher("/user/login.jsp").forward(req, resp);
}
}
}
这里有几个重要的点都写在注释里面了,可以参考一下代码。另外需要注意都就是在web.xml中配置servlet的时候,路径引起的问题。
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.tb.system.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<!-- 实际访问的路径,默认是web文件夹下面,如果页面在其他目录下,需要加上该目录 如果在web下面,直接/LoginServlet就可以 -->
<!--<url-pattern>/user/LoginServlet</url-pattern>-->
<!-- 或者直接把表单指向地址写成这样:action="<%=request.getContextPath()%>/LoginServlet" <%=request.getContextPath()%>指向当前默认目录,就是部署服务器配置的Application context -->
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
可以看到注释里面所说的,而jsp中对应的就是这样(第三行):
<body>
<h1 align="center">用户登录</h1>
<form action="<%=request.getContextPath()%>/LoginServlet" method="post">
<table align="center">
<tr>
<td width="80" align="right">用户名:</td>
<td>
<input id="userName" name="userName" type="text" placeholder="请输入用户名"/>
</td>
</tr>
<tr>
<td width="80" align="right">密码:</td>
<td>
<input id="password" name="password" type="password" placeholder="请输入密码"/>
</td>
</tr>
</table>
<p></p>
<div align="center">
<input name="login" value="登录" type="submit" class="inputText" style="color: #000000" onclick="return check()">
</div>
</form>
</body>
运行结果
现在重新部署一下我们的程序,就可以看到如下运行结果了:
写在最后
到此一个简易的用户登录注册管理系统就实现了,这里只是一个练习项目,如果需要在实际中去应用,还需要很多修改的地方,而且现在都是在用ssm框架去做,所以可以当作一个入门来看,中间也碰到了很多问题,一点一点摸索,花了三四天时间才做完,最后给出源码下载地址:
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/129872.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...