一个小白的SpringBoot快速入门Demo(每日更新中)

目录

0、背景

一、STS环境安装、配置

二、建一个project并完成基本配置

三、啃源码


 

0、背景

因为种种原因,我现在计划用SpringBoot搭建一个网站平台,由于非科班出生,从头系统学的成本太大了,而且也不是很必要,因此决定以项目驱动学习,先在做一个小demo(在网页端操作数据库,实现增删查改)。我之前有过做一个网站的课程设计,前端用的jsp,后端没有用什么框架,连数据用的jdbc,总体而言就是一个小菜鸡水平。

我请了一个软工的外援来帮我,学习路线就是:他大概给了讲了springboot的总体思想,代码中几个重要的部分(我其实并没有太听懂),然后发给了一个他的课程设计的源码,我啃源码,然后动手做自己的demo,遇到问题再问他。

写这篇博客的目的是为了做笔记,一方面方便日后回顾,再者也可以加深理解,如果可以帮助到一些和我一样的入门级小菜鸡就更好啦。我写博客的风格就是详细,博客写完了我会让软工大佬帮忙看一下,确保没有知识点上的差错误人子弟,然后项目源码也会共享滴。

然后,在项目开始前,我已经安装好了Java,maven,mysql。

 

一、STS环境安装、配置

STS下载链接,我这里下载的是STS 3.9.10

下载好了就可以启动这个啦。

启动后,首先选择工作空间。

配置jre和maven。

windows --> preferences  --> java --> installed jre

选自己的Jre目录,然后finish后勾上。

配置maven。

我已经安装好maven了,这里就是选maven的setting.xml的路径

截止到这一步,配置就完事了。

----------------------------------------------------------------------------------------------------------------------

二、建一个project并完成基本配置

new-->new Spring Starter Project

不用设置什么,直接next,然后勾选需要的依赖,然后finish。

然后就可以看到新建好的项目了,简单的看一下目录。

DemoApplication.java:启动类

application.properties:spring boot配置文件

pom.xml:maven配置文件

配置pom.xml

因为我的前端是用jsp,所以要配置一下Jsp,然后在原本生成的配置中还加了一些插件。完整的pom.xml如下:

<?xml version="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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.0</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		
		<!-- 对jsp的支持 -->
        <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>javax.servlet-api</artifactId>    
        </dependency>
        <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>jstl</artifactId>
        </dependency>
        <dependency>
               <groupId>org.apache.tomcat.embed</groupId>
               <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
        	<groupId>org.springframework.boot</groupId>
        	<artifactId>spring-boot-configuration-processor</artifactId>
        	<optional>true</optional>
        </dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<mainClass>com.example.demo.DemoApplication</mainClass>
				</configuration>
			</plugin>
			<plugin>
		        <groupId>org.apache.maven.plugins</groupId>
		        <artifactId>maven-surefire-plugin</artifactId>
		        <configuration>
		          <skip>true</skip>
		        </configuration>
	     	</plugin>
		</plugins>
		
		<resources>
			<resource>
				<directory>src/main/webapp</directory>
				<targetPath>META-INF/resources</targetPath>
				<includes>
					<include>**/**</include>
				</includes>
			</resource>
		</resources>
	</build>

</project>

接下来配置application.properties:

其中springbootDB是我的Mysql数据库名,在spring.datasource.url需要改一下哈。

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springbootDB?serverTimezone=Hongkong
spring.datasource.username=root
spring.datasource.password=lemon

mybatis.mapper-locations=mybatis/mapper/*Mapper.xml

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

然后run一下看看有配置上有没有什么问题。

果不其然,报错了。Failed to configure a DataSource: 'url' attribute is not specified and no embedd

修改办法:

右击项目,build path >> configure build path

把**remove掉就可以了。

成功运行的界面如下:

截止到现在,配置上就完事了。

 

三、啃源码

啃源码的第一步就是认识目录,一共分为7大块吧。这一步我也不打算每一句都啃透

我的小目标是:①明确项目结构(7大块),②各部分大致功能,③各部分大致长啥样。

这里我会贴部分朋友的课程设计的代码,不需要看懂里面的逻辑,大概看一下长啥样就行,具体要自己做时,再依葫芦画瓢吧。

 

1.启动类ExamingApplication

这个建项目的时候自动生成了的,点进去一看,居然没做任何修改。

 

2.工具类

这个是非必须的。

可能有些功能需要有复杂的逻辑处理,然后又会被调用很多次,那就封装成一个工具类咯,方便重复调用。

 

3.实体类

这个是比较好理解的,建立实体类,再给每个属性创建getter和setter。

package com.dn.examing.pojo;

import java.io.Serializable;

public class User implements Serializable{
	private Long id;
	private String username;
	private String password;
	private String phone;
	private Integer age;
	private Integer gender;
	private Integer type;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Integer getGender() {
		return gender;
	}
	public void setGender(Integer gender) {
		this.gender = gender;
	}
	public Integer getType() {
		return type;
	}
	public void setType(Integer type) {
		this.type = type;
	}
}

4.Mapper

mapper里面全是一些接口,在这里直接操作数据库,这里用到了注解。

我以前没接触过注解,但是看样子,注解的内容就是一些sql语句,用到了再详细查吧。(好像并不难的亚子)

package com.dn.examing.mapper;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.dn.examing.pojo.User;

@Mapper
public interface UserMapper {
	@Select("SELECT * FROM tb_user WHERE username=#{username} AND password=#{password}")
	User selectUser(User form);

	@Select("SELECT username FROM tb_user WHERE username=#{username}")
	String selectUserNameByUsername(String username);

	@Insert("INSERT tb_user VALUES(#{id},#{username},#{password},#{phone},#{age},#{gender},#{type})")
	void insertUser(User form);

	@Select("SELECT password FROM tb_user WHERE username=#{username} AND phone=#{phone}")
	String selectPassword(User form);

	@Update("UPDATE tb_user SET password=#{password},phone=#{phone},age=#{age},gender=#{gender} "
			+ "WHERE id=#{id}")
	void updateUser(User form);

}

 

5.Service

这里就是正儿八经的逻辑处理了, 以用户登录为例的话,就包括了根据前端的输入(但是Service并不会直接去接受前端的输入哦!),然后去数据库里面查询密码是否正确之类的,这些业务处理都是在Service里面,Service就像一个干实事的部分。

然后还可以看到,Service会借助Mapper操作数据库。

package com.dn.examing.service;

import java.io.UnsupportedEncodingException;

import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dn.examing.mapper.UserMapper;
import com.dn.examing.pojo.User;

@Service
@Transactional
public class UserService {
	@Autowired
	private UserMapper userMapper;
	
	public User selectUser(User form) throws Exception {
		form.setPassword(new String(Base64.encodeBase64(form.getPassword().getBytes("UTF-8"))));
		User user = userMapper.selectUser(form);
		if(user == null) {
			return user;
		}
		user.setPassword(new String(Base64.decodeBase64(user.getPassword().getBytes("UTF-8"))));
		return user;
	}

	public boolean selectUserNameByUsername(String username) {
		String user = userMapper.selectUserNameByUsername(username);
		if(user == null || user.isEmpty()) {
			return true;
		}
		return false;
	}

	public void insertUser(User form) throws Exception {
		form.setPassword(new String(Base64.encodeBase64(form.getPassword().getBytes("UTF-8"))));
		userMapper.insertUser(form);
	}

	public String selectPassword(User form) throws Exception {
		String password = userMapper.selectPassword(form);
		if(password == null) {
			return password;
		}else {
			password = new String(Base64.decodeBase64(password.getBytes("UTF-8")));
			return password;
		}
	}

	public void updateUser(User form) throws Exception {
		form.setPassword(new String(Base64.encodeBase64(form.getPassword().getBytes("UTF-8"))));
		userMapper.updateUser(form);
		form.setPassword(new String(Base64.decodeBase64(form.getPassword().getBytes("UTF-8"))));
	}

}

 

6.Controller

controller是从前端接收数据,然后把接受的数据交给Service进行处理,然后把Service的处理结果呈现到前端。

从代码片中可以看到,return "homepage";,这里的homepage都是Jsp网页,controller是直接的前端打交道的。

 

package com.dn.examing.controller;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.dn.examing.common.Utils;
import com.dn.examing.pojo.User;
import com.dn.examing.service.UserService;

@Controller
public class UserController {
	@Autowired
	private UserService userService;
	
	@RequestMapping("/login")
	public String login(Model model,User form,HttpSession session) throws Exception {
		User user = userService.selectUser(form);
		if(user == null) {
			model.addAttribute("msg","用户名或密码错误");
			return "login";
		}else {
			session.setAttribute("session_user", user);
			if(user.getType()==0) {
				return "back/homepage";
			}else {
				return "homepage";
			}
		}
	}
	
	@RequestMapping("/register")
	public String register(Model model,User form) throws Exception {
		if(form.getUsername()==null || form.getUsername().length()<4 || form.getUsername().length()>10) {
			model.addAttribute("msg","用户名长度必须在4-10位之间");
			return "register";
		}
		if(form.getPassword()==null || form.getPassword().length()<4 || form.getPassword().length()>10) {
			model.addAttribute("msg","密码长度必须在4-10位之间");
			return "register";
		}
		if(form.getPhone()==null || form.getPhone().length()!=11) {
			model.addAttribute("msg","电话号码必须为11位");
			return "register";
		}
		if(!userService.selectUserNameByUsername(form.getUsername())) {
			model.addAttribute("msg","用户名已存在");
			return "register";
		}
		
		form.setId(Utils.makeId());
		form.setType(1);
		userService.insertUser(form);
		
		return "login";
	}
	
	@RequestMapping("/findPassword")
	public String findPassword(Model model,User form) throws Exception {
		String password = userService.selectPassword(form);
		if(password == null || password.isEmpty()) {
			model.addAttribute("msg","用户名和手机号与注册时不一致");
		}else {
			model.addAttribute("msg","您的密码为:"+password);
		}
		return "findPassword";
	}
	
	@RequestMapping("/editUser")
	public String editUser(Model model,User form,HttpSession session) throws Exception {
		if(form.getPassword()==null || form.getPassword().length()<4 || form.getPassword().length()>10) {
			model.addAttribute("msg","密码长度必须在4-10位之间");
			return "editUser";
		}
		if(form.getPhone()==null || form.getPhone().length()!=11) {
			model.addAttribute("msg","电话号码必须为11位");
			return "editUser";
		}
		
		User user = (User)session.getAttribute("session_user");
		form.setUsername(user.getUsername());
		form.setId(user.getId());
		form.setType(user.getType());
		userService.updateUser(form);
		session.setAttribute("session_user", form);
		
		if(form.getType()==0) {
			return "back/homepage";
		}else {
			return "homepage";
		}
	}
	
	@RequestMapping("/exitLogin")
	public String exitLogin(HttpSession session) throws Exception {
		session.removeAttribute("session_user");
		return "login";
	}
}

 

7.jsp

jsp网页,也就是前端部分。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
	<link href="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/css/bootstrap-theme.css" rel="stylesheet">
	<link href="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/css/bootstrap.css" rel="stylesheet">
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/affix.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/alert.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/bootstrap.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/button.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/carousel.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/collapse.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/dropdown.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/modal.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/popover.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/scrollspy.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/tab.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/tooltip.js"></script>
	<script src="https://cdn.bootcss.com/twitter-bootstrap/3.0.1/js/transition.js"></script>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="container">
		<div class="row clearfix">
			<div class="col-md-12 column">
				<h3 class="text-center">
					用户登录
				</h3>
				<form role="form" action="/login" method="post">
					<div class="form-group">
						 <label>用户名</label>
						 <input type="text" class="form-control" name="username" />
					</div>
					<div class="form-group">
						 <label>密码</label>
						 <input type="password" class="form-control" name="password" />
					</div>
					<button type="submit" class="btn btn-default">登录</button>
				</form>
				<h3 class="text-info">
					<a href="/toRegister">点击此处前往注册</a>
				</h3>
				<h3 class="text-info">
					<a href="/toFindPassword">找回密码</a>
				</h3>
				<h3 class="text-center text-warning">
					${msg }
				</h3>
			</div>
		</div>
	</div>
</body>
</html>

啃源码的第二部就是掌握各部分是怎么联动起来的。

以用户登录为例子,串一串各部分是怎么连动起来的叭。

1.login.jsp里面有一个表单,有两个input的name分别是username和password,输入用户名和密码。提交表单会执行/login

2.一旦表单提交了,就要执行/login,因为注解的绑定,对应的controller就要开始干活了。

该方法有一个参数User form,它会自动和表单里面的username和password匹配上,为什么会自己匹配上呢,是因为User里面有username和password这两个属性,由于名称上的严格一致,他们就像磁铁一样的匹配上了。

然后再login方法里面,会创建一个UserService的对象,调用里面的selectUser方法干实事,看看数据库里面有没有这个用户。如果有,去homepage页面,如果没有,去login页面,这里return的都是jsp页面

 

3.在UserController里面,调用了UserService。

UserService会根据传入的参数,去数据库里面进行查找,根据查找结果进行一些逻辑处理,然后返回处理后的结果

具体执行查询动作,会调用UserMapper的方法。

4.mapper就是一个没有感情的数据库操作员,里面全是接口,然后注解里面是Sql语句。mapper会返回数据库里找到的东西

5.然后mapper里面的东西传给service,service里面的东西传给controller,最后controller控制前端的跳转。这里的return都是jsp页面。

整个流程大概如下:

因此是第一次接触SpringBoot,也是第一次接触框架,所以在了解这个用户登录过程,我遇到了如下问题:

Q1:UserController是一个类,但是在整个项目代码里面也没有创建一个它的对象去显式的调用它的login方法,login方法怎么被调用的呢??

A1:大佬给我说其实是底层DispatcherServlet调用的,只不过被封装了看不到。再能看到的代码中,用户登录表单的action:/login,和UserController中的login方法由于@RequestMapping("/login")注解联系了起来。

 

Q2:登录按钮都没有设置点击监听器,怎么被点击了就会执行对应的方法呢?

A2:我已经太久没碰前端了,对表单也是极其不熟悉啊!!form表单中有一个button type="submit",然后表单action="/login"  method="post",表单被提交了,自动会跳转到/login。

 

Q3:前端传入的数据(username,password)怎么就被UserController中的login方法接收到了呢??

A3:login方法的参数有User form,其中user有username,password属性,由于二者名称上的严格一致就对应上了。真的很神奇。也可以不是User类,String也行的,只要是变量名称和username,password严格对应就行。

截止到现在,对SpringBoot的模块和运行流程有个大概了解了,明天开始自己动手做demo。冲鸭!

 

四、demo设计

因为主要是我为了摸清楚Spring boot,所以前端就没有任何美工了,非常的简单粗暴。

这个demo呢,是一个班级人员管理,实体就是Student(id,name),然后在不同的界面实现班级人员的增删查改。

homepage.jsp

主页四个button,点击后跳到响应的网页。(这里就算练习了页面跳转)

insert.jsp

delete.jsp

select.jsp

update.jsp

具体的操作情况,简单得我说你都能猜到哈哈哈。

 

五、demo编程实现

1.数据库建表

2.编写实体类

package com.example.demo.pojo;

public class Student {
	private String id;
	private String name;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
		
}

3.写前端代码

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章