- 转眼间已经来到公司一个月了,一直都没时间写博客,今天趁着自己调试到心态爆炸,又正好积累了一堆bug经验,赶快记录一下.
- 先感叹一下,在公司和学校效率完全不是一个层次,工作催动可比作业催动快多了.
- 今天是接触springboot框架的第三天,看了几个项目,终于完全自行实现了一次登录功能,虽然很简陋,还是挺开心的.
下面就开始很详细的讲解了:
首先当然是建立数据库表,我建立了一个非常简单的数据库表user,只有三个字段,账户名,密码和访问级别(因为马上要做权限管理嘛)
- 然后就是建立项目了,总而言之就是用spring start功能,导入web,jdbc,mysql,mybatis(我现在只知道是用来绑定mapper和xml的,持久层框架.)
这里最重要的是要一行一行的讲清楚
配置文件yml
到底在干什么.
你们如果要复制就把所有汉字删掉就行,注意在配置文件中最好连汉字注释都不要出现,容易报不知道什么鬼的错
server:
port: 8080 //简单就是服务器端口号,在springboot里直接访问端口号,
//springboot会去检测resource文件夹下static文
//件夹下里有没有叫index.html的,会做为这个端
//口号的欢迎页,简而言之就是你去访问端口号就会展示欢迎页
注意属性和值之间要有空格,属性和子属性之间有两个空格
spring:
datasource://数据源嘛
url: jdbc:mysql://localhost:3306/demodb?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=false&useSSL=false
//在这里我就要爆炸了,cj.jdbc要放时区,而且时区很容易出错,反正很烦
username: root//账号密码没什么好说的
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver//注意版本不同是有时区之分的
mybatis:
mapper-locations: classpath:mapper/*.xml //持久层框架,很重要哦,这一行是确定你的xml(就是增删改查)文件要到哪里去找,xml文件一般都放在resources下面mapper文件夹.
type-aliases-package: com.vanchip.model //注意,这是要绑定实体类的,反正不能填错
logging:
level:
org.springframework.web: TRACE //日志级别,最重要的功能是看映射地址
spring.thymeleaf.prefix: classpath:/templates/ 前端框架,目前还不太会用,不过这两行代码很明显了,就是说我的文件是去哪里找,这文件是html就完事了
spring.thymeleaf.suffix: .html
建包分层
**了,你以为这是很常见的,所以就没什么坑了吧,想多了,一定要保证包名一致.
大概应该是这类型的,如果包名的格式不是很正确,然后就会发现,springboot一会扫不到配置类,一会又扫不到service,因为要依赖注入嘛,所以,我们只使用抽象类就行,有框架进行依赖注入,把实现类导进去.
分层结构差不多也是这样.
聪明的孩子会发现少了一个controller层,为什么呢?因为我一开始设置了controller层,然后悲剧的发现根本就映射不到.
这里有一个知识点;controller层必须放在启动类的子包或者同级才能被检测到,才能实现映射,我在这卡了半天,抓狂
所以正常情况下建议启动类直接拖到分层包外面去,应该是最安全的.
**
分层架构
**(自己的理解)
我是推荐新人阅读代码最好要分层来读,跟着一个附带增删改查的功能从头追到尾,而且尽量不要横向发展,否则会很晕的.
一个请求从浏览器发出,到被拦截器拦截,然后拦截器分配一下地址,不对的访问就给你转发到登录页面.对的基本就是游客身份登录或者怎样.
然后 在进入登录界面以后,你的登录信息会作为表单也好,参数也罢,开始被controller层接收
超简单的前端
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>administer,welcome to login Vanchip exam-online system!</title>
</head>
<body>
<form method="post" action="admin/login">//表单访问的映射地址\以及传输方式
<label>welcome! administer!</label>
<p>
<input type="text" value="请输入您的账户" name="username" id="username">//注意name是要传到服务器的属性,id主要是前端样式用的
</p>
<input type="text" value="请输入您的密码" name="password" id="password">
<p>
<input type="submit" value="登录" >//就是提交表单嘛.
</p>
</form>
</body>
</html>
然后当你提交表单之后,服务器将你的信息提交到映射处,也就是
controller层
package com.vanchip.logintest;
import java.lang.ProcessBuilder.Redirect;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.vanchip.model.User;
import com.vanchip.service.UserService;
@RequestMapping("/admin")//整个类的映射地址,后面方法映射地址是叠加的
@Controller//告诉springboot这是controller层,记得把映射搞上去
public class LoginController {
@Autowired//这里是调用的service抽象层的类,以后用,这里的@Autowired应该是说把service实现层的方法加载到这个抽象层容器里
UserService UserService;
@ResponseBody //加上这个注解,返回的就不是地址了,而是一段文本,我这只是看下成功没,正常应该在成功后跳转到其他页面
@RequestMapping("/login")//映射嘛
public String login(@RequestParam(name = "username", required = true) String username,
@RequestParam(name = "password", required = true) String password, HttpServletRequest req,
HttpServletResponse res) {//在这里引入了参数,也就是前端传进来的参数,似乎@RequestParam可以去找传进来的参数,当然是用name进行匹配了,
//下面两个对象,我其实不知道为啥要加,但是调试的时候总是出错,然后试了一下设置返回文本的格式居然就可以了,我^&*&
res.setCharacterEncoding("utf-8");
User user = UserService.login(username, password);//调用service层抽象类方法,返回一个承接了数据库返回值的实体类
if (user != null) {//很简单的逻辑,返回的只要不是空值就说明是存在的,ok
System.out.println(user.toString());
return "welcome adminster!" + user.toString();//返回一段文本
}
return "/err";//返回到另一个界面,但是目前还没做
}
@RequestMapping("/s")
@ResponseBody
private String sen(String info) {
return info;
}
@RequestMapping("/err")
@ResponseBody
private String err() {
return "登录失败";
}
}
那么,应该会注意到,controller核心接收前后端数据并且返回,总而言之就是通信层.在这个登录方法里最重要的是service层的方法返回值是怎么样的.
service抽象层
package com.vanchip.service;
import org.springframework.stereotype.Service;
import com.vanchip.model.User;
public interface UserService {
User login(String username, String password);//就把方法写上去,参数返回值就没了
}
service实现层
package com.vanchip.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.vanchip.mapper.userMapper;
import com.vanchip.model.User;
import com.vanchip.service.UserService;
@Service//注意需要进行注解,不然是扫描不到这是实现层的
public class UserServiceImpl implements UserService {
//我个人觉得其实springboot是通过接口引用来确定谁是要装载的抽象层的.
@Autowired
userMapper userMapper;//没什么说的,还是自动装载了mapper抽象层
@Override
public User login(String username, String password) {
User user = userMapper.getbycond(username, password);//使用了mapper层方法,现在看着简单和多此一举,但实际上,等业务逻辑复杂就不是简单引用方法,
//而是要对mapper层增删改查加上算法和业务逻辑写在这里才行.
return user;
}
}
mapper抽象层
package com.vanchip.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.vanchip.model.User;
@Mapper
public interface userMapper {
//@Param("username") @Param("password") //我原来看他们还写了参数叫什么,但是我发现好像反而会造成mapper实现层参数混乱,我去掉就正常了
User getbycond(String name,String pwd);
}
mapper实现层
这是增删改查放的地方
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.vanchip.mapper.userMapper">//注意命名空间就是框架绑定的依据哈
<sql id="base_table">
user//这是定义了一个属性,方便重复利用罢了
</sql>
<select id="getbycond" resultType="com.vanchip.model.User">
select * from
<include refid="base_table" />
where id=#{name,jdbcType=VARCHAR}//这就是简单的上个参数和在数据库里的类型,会自动调成实体类能接受的类型
and
password=#{pwd,jdbcType=VARCHAR}
</select>
//这就是核心部分了,id是说和抽象层哪一个方法绑定,返回值把实体类拉进来自动去绑,而且会根据数据库和实体类自动调整哦.
</mapper>
实体类
没什么好说的,不过放上来把
package com.vanchip.model;
import java.io.Serializable;
@SuppressWarnings("serial")
public class User implements Serializable {
String id;
String password;
Integer accesslevel;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAccesslevel() {
return accesslevel;
}
public void setAccesslevel(Integer accesslevel) {
this.accesslevel = accesslevel;
}
@Override
public String toString() {
return String.format("当前登录账户为"+id+",密码为 %s,访问等级为 %d", password, accesslevel);
}
}
最后的重点启动类
package com.vanchip.logintest;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.vanchip.mapper")//表明mapper抽象层在哪里,方便装配
@SpringBootApplication(scanBasePackages = {"com.vanchip"})//表明你的各种包在哪里
public class LogintestApplication {
public static void main(String[] args) {
SpringApplication.run(LogintestApplication.class, args);
}
}