目录
一、开发前准备
二、设计登录页面(小程序)
三、创建 Maven 项目
四、创建数据库与数据表
五、后台代码(Java Servlet)
六、运行
七、总结 建议
1、注册一个微信开发者账号:https://open.weixin.qq.com (略)
2、开发工具:idea、Mysql、微信开发者工具
3、应用技术:Java(后台)、小程序(前端)、Maven、Mysql、跨域
4、本次案例以功能为主,页面效果能用就行(不注重页面设计)
注意:创建小程序的项目和Javaweb项目我都略过了详细的创建步骤(可能刚开始的小白会不懂怎么创建,我刚开始接触小程序的时候也是一样,创建项目都弄了好久),如果有需要的话,后面我会做一个 文章详细介绍。
1、login.wxml(设计登录页面的文件)
页面效果:
2、login.js(完成登录的逻辑代码)
这里的代码基本上每一行我都注释了,每一行代码的意思都写的很清楚了,方便大家的阅读
(在我们开发编程的过程中,一定要养成写注释的习惯,这样会方便我们之后的阅读,出现 BUG了也能更快的找到问题所在)
// pages/login/login.js
Page({
/**
* 页面的初始数据
*/
/**
* 页面的初始数据
*/
data: {
account:null,
password:null,
},
/**
* 从文本框中得到输入的值
* 获取账号的方法
*/
userAccount:function(event){
// 获取文本框输出的账号
var userAccount = event.detail.value;
this.setData({
// 把获取到的账号赋值给 account 变量
account:userAccount,
})
console.log(this.data.account)
},
// 获取密码的方法
userPassword:function(event){
// 获取文本框输出的密码
var userPassword = event.detail.value;
this.setData({
// 把获取的密码赋值给 password 变量
password:userPassword,
})
console.log(this.data.password)
},
// 点击登录按钮要做的事情
loginTap:function(){
wx.request({
// 接口地址:登录的 servlet 地址
url: 'http://localhost:8080/项目名/XXX.do',
// 向后端传递的数据
data: {
// 账号
x:this.data.account,
// 密码
y:this.data.password,
},
// 以HTTP协议传HTML资料到浏览器前所送出的字串
header: {
//'content-type': 'application/json' //默认值
'Content-Type': 'application/x-www-form-urlencoded'
},
// 以什么方法传递(常用的是:POST、GET)
method: 'POST',
// 成功之后要做的操作
success(res) {
// 这里输出了登录的用户名
console.log(res.data.user_name)
console.log('----successed----')
// 判断是否存在数据,成功就跳到下一个页面
if(res){
/**
* 1、wx.navigateTo
保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。
2、wx.redirectTo
关闭当前页面,跳转到应用内的某个页面。
3、wx.switchTab
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
4、wx.navigateBack
关闭当前页面,返回上一页面或多级页面。可通过 [getCurrentPages()] 获取当前的页面栈,决定需要返回几层。
5、wx.reLaunch
关闭所有页面,打开到应用内的某个页面。
*/
wx.redirectTo({
// 跳到成功页面
url: '/pages/HomePage/homePage',
})
}
},
// 失败
fail(res){
// showModal:模态对话框
wx.showModal({
title:'提示',
content:'登录失败,账号或密码错误',
success(req){
if(res.confirm){
console.log("用户点击了确定",res);
} else if(res.cancel){
console.log("用户点击了取消");
}
}
})
console.log('----fail----')
}
})
},
// 点击了注册按钮
rigestTap:function(){
wx.showModal({
title:'提示',
content:'这是注册功能',
success(res){
if(res.confirm){
wx.redirectTo({
// 跳到注册页面
url: '/pages/register/reg',
})
} else{
console.log("点击了取消按钮");
}
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
为什么要选择使用 Maven 呢? 因为我们开发需要使用很多的 jar 包,每需要一个就需要去下载一个,还要在项目配置中添加进去,操作非常繁琐,所以我们使用 Maven 来对我们的项目依赖我们需要的 jar 包,只需要到网上复制到 pom.xml 文件中就可以使用该 jar 包的 API 方法。
1、首先我们要创建一个Maven项目,这里我选择的是 Java ,但是我们需要的是web项目,后面我在项目结构中创建 web 项目
2、把我们的项目创建为 web 项目
步骤:点击我们软件的设置按钮 ----- Project Structure
3、配置pom.xml文件
下载依赖的网址:Maven Repository: Search/Browse/Explore (mvnrepository.com)
注意:一定要记得把我们的打包方式设置为 war 包,因为我们这次的项目为 web项目
1、junit依赖:
用途:
1、进行单元测试,测试一个方法或者类是否能够正常运行
略.......
2、servlet依赖:
用途:
1、允许程序员注册一个类,在 Tomcat 收到的某个特定的 HTTP 请求的时候,执行这个类中的一些代码
2、帮助程序员解析 HTTP 请求,把 HTTP 请求从一个字符串解析成一个 HttpRequest 对象
3、帮助程序员构造 HTTP 响应,程序员只要给指定的 HttpResponse 对象填写一些属性字段,Servlet 就会自动的按照 HTTP 协议的方式构造出一个 HTTP 响应字符串,并通过 Socket 编写返回给客户端
3、MySQL依赖:
用途:
1、MySQL依赖是用于Java程序中连接和操作MySQL数据库的工具包
4、lombok依赖:
用途:为我们的实体类省去重复的代码
1、@Data 不需要写getter setter
2、@NoArgsConstructor 无参构造方法
"1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>untitled1artifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>11maven.compiler.source>
<maven.compiler.target>11maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.33version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.26version>
<scope>providedscope>
dependency>
dependencies>
project>
-- 创建数据库
create database psm;
-- 使用数据库
use pms;
-- 创建数据表:userInfo
-- if not exists userInfo:判断userInfo表是否存在,不存在则创建
create table if not exists userInfo(
UserId int primary key auto_increment, -- 用户ID
userName varchar(20) , -- 账号
userPwd varchar(32), -- 密码(我们要使用MD5加密,加密后密码长度为32位)
picture varchar(200) -- 头像
);
select * from userInfo;
1、创建用户实体类
是不是觉得我们的实体类少了很多代码,没错,这就是 Lombok 帮我们省去了
package entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Date 2023-04-25
* @Author qiu
*/
@Data // 生成get\set
@NoArgsConstructor // 无参构造方法
@AllArgsConstructor // 有参构造方法
public class UserInfo {
/**
* 账号
*/
String userName;
/**
* 密码
*/
String userPwd;
/**
* 头像
*/
String picture;
}
2、SqlRunner执行器(增、删、改、查操作的封装)
对JDBC 进行封装,封装后我们就不再需要写那7个恶心的步骤了,省去了大量的重复代码。
package runner;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* SqlRunner 执行器 - 执行 增、删、改、查操作
* *
* * 更新操作:insert、update、delete
* * 查询操作:select
* @Date 2023-04-25
* @Author qiu
*/
public class SqlRunner {
private Connection connection;
public SqlRunner(Connection connection) {
this.connection = connection;
}
/**
* 通用更新操作:执行 增、删、改的 SQL 语句
*
* insert into staffs(name,age,phone,sta_pos)
* values (?,?,?,?) ;
*
* @param sql
* @param params 不定长参数,本质上是一个数组
* @return
*/
public int executeUpdate(String sql, Object... params) {
// 第一:获取连接对象
if (connection == null) {
throw new RuntimeException("连接对象为null");
}
// 第二:预编译SQL语句
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(sql);
// 第三:填充参数
setParameter(ps, params);
// 第四:执行SQL语句
// 第五:返回结果
return ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
// 第六:关闭相关的对象
close(ps);
close(connection);
}
}
/**
* 填充 SQL 语句中的占位符数据
*
* @param ps
* @param params
* @throws SQLException
*/
private static void setParameter(PreparedStatement ps, Object[] params) throws SQLException {
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
}
/**
* 返回实体对象的属性名称
*
* @param clazz 实体对象的 Class 对象
* @param columnLabel select 后面的名称
* @param
* @return
*/
private String getFieldName(Class clazz, String columnLabel) {
// 1.获取实体对象所有的字段对象
Field[] fields = clazz.getDeclaredFields();
// 2.循环遍历字段数组
for (Field field : fields) {
// 3.判断字段是否存在 Column 注解
boolean isExist = field.isAnnotationPresent(Column.class);
// 4.如果存在,则获取注解的内容
if (isExist) {
String columnName = field.getAnnotation(Column.class).value();
// 5.判断注解的内容是否与 select 后面的字段名称一样
if (columnName.equals(columnLabel)) {
// 6.如果一样,则返回字段名称 - staPos
return field.getName();
}
}
}
// 7.如果不一样,则返回 select 后面的字段名称
return columnLabel;
}
/**
* 通用查询操作 - 返回的List集合
*
* @param clazz 实体对象的Class对象
* @param sql 要执行查询语句
* @param params 查询语句点位符数据
* @param T为具体的实体类型对象
* @return 返回的List集合
*/
public List executeQuery(Class clazz, String sql, Object... params) {
List list = new ArrayList<>();
// 第一:获取连接对象
if (connection == null) {
throw new RuntimeException("连接对象为null");
}
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 第二:预编译SQL语句
ps = connection.prepareStatement(sql);
// 第三:填充参数
setParameter(ps, params);
// 第四:执行SQL语句 - ResultSet
rs = ps.executeQuery();
// 第五:获取结果集元数据对象
ResultSetMetaData metaData = rs.getMetaData();
// 第六:获取查询字段的数量
int count = metaData.getColumnCount();
// 第七:对结果集进行处理 - 遍历结果集,读取结果集中的数据,封装到List集合
while (rs.next()) {
// 1.实例化实体对象 - 思考:实体对象是谁呢? - 在这里,谁都可以,我们要做一个通用的查询 - 通过 clazz 这个参数来确定要操作的具体实体对象的Class对象
T entity = clazz.getConstructor().newInstance();
// 2.读取结果集各列的数据 - 思考:有几列数据?是不确定的 - 解决? - ResultSetMetaData
// Object xxx = rs.getObject("yyy") ;
for (int i = 1; i <= count; i++) {
// 2.1)获取查询字段名称 - 必须和实体对象的属性名称保持一致 - sta_pos、add_time
String name = getFieldName(clazz, metaData.getColumnLabel(i));
// 2.2)根据名称获取实体对象的字段对象
Field declaredField = clazz.getDeclaredField(name);
// 2.3)设置字段访问权限
declaredField.setAccessible(true);
// 2.4)获取结果集中的数据
Object obj = rs.getObject(i);
// 2.5)封装数据到实体对象中 - 思考:获取数据后,给对象的哪个属性初始化呢? - 反射
declaredField.set(entity, obj);
}
// 3.把实体对象添加到 List 集合中
list.add(entity);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 第八:关闭对象
close(rs);
close(ps);
close(connection);
}
return list;
}
/**
* 查询数据,返回数据表的一行数据
*
* @param clazz
* @param sql
* @param params
* @param
* @return
*/
public T query4Entity(Class clazz, String sql, Object... params) {
T entity = null;
// 第一:获取连接对象
if (connection == null) {
throw new RuntimeException("连接对象为null");
}
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 第二:预编译SQL语句
ps = connection.prepareStatement(sql);
// 第三:填充参数
setParameter(ps, params);
// 第四:执行SQL语句 - ResultSet
rs = ps.executeQuery();
// 第五:获取结果集元数据对象
ResultSetMetaData metaData = rs.getMetaData();
// 第六:获取查询字段的数量
int count = metaData.getColumnCount();
// 第七:对结果集进行处理 - 遍历结果集,读取结果集中的数据,封装到List集合
if (rs.next()) {
// 1.实例化实体对象 - 思考:实体对象是谁呢? - 在这里,谁都可以,我们要做一个通用的查询 - 通过 clazz 这个参数来确定要操作的具体实体对象的Class对象
entity = clazz.getConstructor().newInstance();
// 2.读取结果集各列的数据 - 思考:有几列数据?是不确定的 - 解决? - ResultSetMetaData
// Object xxx = rs.getObject("yyy") ;
for (int i = 1; i <= count; i++) {
// 2.1)获取查询字段名称 - 必须和实体对象的属性名称保持一致 - sta_pos、add_time
String name = getFieldName(clazz, metaData.getColumnLabel(i));
// 2.2)根据名称获取实体对象的字段对象
Field declaredField = clazz.getDeclaredField(name);
// 2.3)设置字段访问权限
declaredField.setAccessible(true);
// 2.4)获取结果集中的数据
Object obj = rs.getObject(i);
// 2.5)封装数据到实体对象中 - 思考:获取数据后,给对象的哪个属性初始化呢? - 反射
declaredField.set(entity, obj);
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 第八:关闭对象
close(rs);
close(ps);
close(connection);
}
return entity;
}
/**
* 关闭结果集对象
*
* @param rs
*/
private void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
/**
* 关闭语句对象
*
* @param stmt
*/
private void close(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
/**
* 关闭结果集对象
*
* @param conn
*/
private void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
3、接口类(定义登录和注册的方法)
package dao;
import entity.UserInfo;
/**
* @Date 2023-04-25
* @Author qiu
*/
public interface UserDao {
/**
* 登录的方法
*/
UserInfo login(String account,String password);
/**
* 注册账号的方法
*
*/
int insert(String account,String pwd,String prictrue);
}
4、接口实现类(实现接口后,完成接口中的方法的功能)
package dao.daoImpl;
import dao.UserDao;
import entity.UserInfo;
import runner.SqlRunner;
import utils.DbUtil;
/**
* @Date 2023-04-25
* @Author qiu
*/
public class UserDaoImpl implements UserDao {
// 实例化 SQL Runner 对象 - 提供了增、删、改、查
SqlRunner sqlRunner = new SqlRunner(DbUtil.getConnection());
/**
* 实现登录的方法
* @param account 账号
* @param password 密码
* @return
*/
@Override
public UserInfo login(String account, String password) {
String sql = "select userName,userPwd from userInfo where userName = ? and userPwd = ?";
return sqlRunner.query4Entity(UserInfo.class,sql,account,password);
}
/**
* 用户注册的方法
* @param account
* @param pwd
* @return
*/
@Override
public int insert(String account, String pwd,String prictrue) {
String sql = "insert into userInfo(userName,userPwd,picture) values(?,?,?)";
return sqlRunner.executeUpdate(sql,account,pwd,prictrue);
}
}
5、连接数据库的工具类(DbUtil)
package utils;
import java.sql.*;
/**
* 连接数据库 & 释放相关对象
*
*
*
* @Date 2023-03-29
* @Author qiu
*/
public class DbUtil {
/**
* 连接驱动程序
*/
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
/**
* 连接URL
*/
private static final String URL = "jdbc:mysql://localhost:3306/pms?useUnicode=true;characterEncoding=utf8;serverTimezone=Asia/Shanghai";
/**
* 帐号
*/
private static final String USER = "账号";
/**
* 密码
*/
private static final String PASS = "密码";
static {
/*
* 加载驱动程序
*/
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
System.out.println("加载驱动程序失败...");
e.printStackTrace();
}
}
/**
* 获取连接对象 -- Java程序 与 数据库之间的桥梁
*
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(URL, USER, PASS);
} catch (SQLException e) {
System.out.println("获取连接对象失败...");
e.printStackTrace();
}
return conn;
}
/**
* 关闭相关的 JDBC 对象
*
* DriverManager:驱动管理对象,获取连接对象
*
* DriverManager.getConnection(URL, USER, PASS);
*
* ResultSet:结果集对象 用于接收查询数据时,返回的结果
*
* Statement:语句对象 用于执行SQL语句(PreparedStatement、CallableStatement)
* 增、删、改:executeUpdate() 查询:executeQuery()
*
*
* Connection:连接对象 建立JAVA程序与数据库之间的桥梁
*
* @param rst
* @param stmt 父类对象可以接收子类对象 - 多态
* @param conn
*/
public static void close(ResultSet rst, Statement stmt, Connection conn) {
if (rst != null) {
try {
rst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// executeUpdate()、executeQuery() - 略
public static void main(String[] args) {
System.out.println(DbUtil.getConnection());
}
}
6、登录的Servlet
package servlet;
import dao.daoImpl.UserDaoImpl;
import entity.UserInfo;
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 java.io.IOException;
import java.io.PrintWriter;
/**
*
* 用户登录的 servlet
*
* @Date 2023-04-25
* @Author qiu
*/
@WebServlet("/login.do")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取小程序端传递过来的数据并打印输出
String account = req.getParameter("x");
String password = req.getParameter("y");
// 判断 账号和密码不为空
if (account != null && password != null) {
// 实例化 UserDaoImp
UserDaoImpl userDao = new UserDaoImpl();
// 调用登录的方法进行登录
UserInfo login = userDao.login(account, password);
System.out.println("登陆成功");
PrintWriter writer = resp.getWriter();
writer.write("你好");
} else {
System.out.println("账号密码为空");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
7、跨域过滤器
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Date 2023-04-26
* @Author qiu
*/
@WebFilter("/servlet/*")
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("跨域访问--初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 向下转换类型
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
// 解决跨域问题
// 允许所有的域名
String origin = req.getHeader("origin");
resp.setHeader("Access-Control-Allow-Origin", origin);
// 允许发送cookies
resp.setHeader("Access-Control-Allow-Credentials", "true");
// 允许请求所有的方法
resp.setHeader("Access-Control-Allow-Methods", "*");
// 预检请求的最大超时(有效)时间为3600秒
resp.setHeader("Access-Control-Max-Age", "3600");
// 定义可以返回的头部信息字段
resp.setHeader("Access-Control-Allow-Headers", "Authorization,Origin,X-Requested-With,Content-Type,Accept,"
+ "content-Type,origin,x-requested-with,content-type,accept,authorization,token,id,X-Custom-Header,X-Cookie,Connection,User-Agent,Cookie,*");
resp.setHeader("Access-Control-Request-Headers", "Authorization,Origin, X-Requested-With,content-Type,Accept");
// 可以暴露给外部所有头部信息字段
resp.setHeader("Access-Control-Expose-Headers", "*");
// 过滤器放行
filterChain.doFilter(req, resp);
}
@Override
public void destroy() {
System.out.println("跨域访问--销毁");
}
}
8、防止页面乱码的过滤器
package filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CharEncodingFilter implements javax.servlet.Filter {
// 定一个变量存编码
private String encoding;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// filterConfig:读取过滤器的一些配置信息
String encoding = filterConfig.getInitParameter("encoding");
this.encoding = encoding;
System.out.println("中文处理....初始化" + encoding);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 父接口转为子接口
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 设置请求
req.setCharacterEncoding(encoding);
// 设置响应对象的编码
resp.setCharacterEncoding(encoding);
//resp.setContentType("text/html;charset=" + encoding);
// 放行
chain.doFilter(req, resp);
}
@Override
public void destroy() {
System.out.println("中文编码销毁....");
}
}
还需要配置xml,星号表示全部servlet都可用
CharEncodingFilter
filter.CharEncodingFilter
编码设置
encoding
UTF-8
CharEncodingFilter
/*
好啦,到这里我们的登录功能的所有准备和代码都已经完成了,那么怎么执行我们的服务器(TomCat)呢?怎么去登录呢?
其实,和我们之前写 web 项目一样,只不过现在我们是用微信小程序来设计页面,后台代码还是我们熟悉的JavaServlet。我们只需要运行我们的猫就可以了
1、直接点击运行,开启服务器
2、运行页面 404?
运行之后是不是发现页面报错啦,没关系,这是因为我们没有在web项目中写我们的页面,我们的页面在小程序中设计了,如果不行看到这个错误的话,可以在项目中随便写一个页面就ok啦!
3、运行小程序的登录页面
1、输入账号密码进行登录
2、登录成功后跳转页面
3、后台提示
好啦,到这里我们的小程序+ Java 的登录 DEMO已经完成了。
这次没有使用到MD5加密和文件上传的工具类,我打算在下一章的注册功能中再实现代码给到大家。
1、我是在学校学习Java后台开发的学生,只是这段时间老师讲的内容不是很多,就自己开始学习一点课外的知识来充实自己的知识库。
2、大家在学习的时候呢,不要盲目的学习,要有目标性去学,才会从中获取到自己想要的。不要学这个学一下,学那个又学一下,这样只会让自己什么都学不到,我就试过这样了,看这个新鲜就学这个,看哪个新鲜又学哪个,到最后什么都没有学会。就会觉得自己什么都学不好,所以大家在学习过程中一定要专注一门课程,等你学会了,再去学别的。
3、本次是自己第一次发布博客,没有经验,全靠自己的感觉去写,如果有写的不好的,请各位大佬指出,我会及时更正!