从零开始建站(四) - 后端项目搭建

简介:

这节聊一聊项目的后端,之前也讲过,因为对前端不熟悉,所以在前端花了太多的时间,导致到后端开发的时候搞的人有点疲,所以很多东西从简了,很多细节东西没有考虑,只想着把基本功能做出来就好了。框架选择的是现在比较流行的Springboot+Mybatis+Tomcat+MySQL,Springboot是在Spring的基础上做了集成和配置简化,使用起来超级舒服。

一、搭建Springboot框架

1. 框架简介

Springboot是现在非常火热的JavaEE框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程,为什么这么说呢,看一下他的几个特点:

>_> 嵌入的Tomcat,无需部署WAR文件

>_> 简化Maven配置

>_> 自动配置Spring

>_> 提供生产就绪型功能,如指标,健康检查和外部配置

>_> 对XML也没有配置要求比较灵活

然后我们选择Maven来管理我们的JAR包,这个没什么好说的,以后我们用一个pom文件就可以走天下了,不用在背着沉重的JAR包到处跑。

2. Springboot项目初始化

快速创建Springboot可以使用 https://start.spring.io/网页版生成项目然后导入Eclipse中或者使用IDEA创建,这里我们选择前者:首先我们访问 https://start.spring.io/ ,然后按照顺序选择填写:

从零开始建站(四) - 后端项目搭建_第1张图片

1. 项目管理工具,现在一般使用Maven来管理

2. 项目开发语言

3. 这是Springboot版本

4. 项目唯一标识,可以用来确定下面的包名

5. 项目名称

6. 项目包名、打包方式、java版本

7. 项目依赖:下面勾选对应的依赖,这里我只选了web可以视自己情况而定

8. 生成项目

从零开始建站(四) - 后端项目搭建_第2张图片

这里直接生成yytf.zip包,我们解压后用eclipse使用导入maven项目方式导入项目(这里要注意刚导入后项目目录不是下图中这种结构,要等一会jar包下载完成后才会形成如下图结构),如下图目录就是导入后的目录结构,而pom文件里的参数也是我们之前在网页填写的对号入座

从零开始建站(四) - 后端项目搭建_第3张图片

然后我们找到项目的启动文件,这里是BlogApplication.java,右键run as使用java application运行,控制台出现Started BlogApplication in 2.101 seconds (JVM running for 2.455)则springboot启动成功。

从零开始建站(四) - 后端项目搭建_第4张图片

二、项目配置

1. 配置pom.xml引入需要的JAR包


	
	
		org.springframework.boot
		spring-boot-starter-web

		
		
			
				org.springframework.boot
				spring-boot-starter-logging
			
			
			
				org.springframework.boot
				spring-boot-starter-tomcat
			
		
	
		
	
	
	
		org.springframework.boot
		spring-boot-starter-tomcat
		provided
	
		
	
	
		org.springframework.boot
		spring-boot-starter-log4j2
	
		
	
	
		org.mybatis
		mybatis
		3.4.1
	
	
		org.mybatis.spring.boot
		mybatis-spring-boot-starter
		1.3.1
	
		
	
	
		mysql
		mysql-connector-java
		8.0.11
	
		
	
	
		com.auth0
		java-jwt
		2.2.0
	

	


	blog
	
		
			src/main/java
			
			
				**/*.xml
			
		
		
		
			src/main/resources
		
	

2. 配置外部tomcat部署项目

2.1 maven依赖配置

首先我们把打包方式改成war,在pom.xml把 jar 修改成 war 在上面的pom.xml中已经写清楚两种使用外部tomcat方式:第一种是去掉springboot内置的tomcat,第二中时在运行时使内部tomcat失效

2.2 修改启动类

在Application.java中继承SpringBootServletInitializer并重写configure方法

package com.yytf;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.scheduling.annotation.EnableScheduling;

@MapperScan("com.yytf.dao")
@SpringBootApplication
@EnableScheduling
public class Application extends SpringBootServletInitializer{
	
	@Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

3.配置generatorConfig.xml自动生成vo,dao,mapper

3.1在pom.xml中修改build标签,代码上面已贴出

3.2 首先安装eclipse插件:Mybatis Generator 1.3.5

Eclipse => Help => Eclipse Marketplace 搜索mybatis安装最新版本

从零开始建站(四) - 后端项目搭建_第5张图片

3.3 生成generatorConfig.xml文件

New一个文件,然后选择mybatis generator configuration file,然后选择到generatorConfig.xml文件要保存的位置,例如这里保存到\blog\src\main\resources下面

从零开始建站(四) - 后端项目搭建_第6张图片

从零开始建站(四) - 后端项目搭建_第7张图片

3.4 配置generatorConfig.xml文件,这里注意mysql驱动包要使用绝对路径,targetProject为生成文件位置,容易出错:





	
	
	
	

			
				
				
			

			
			
			
			
			

			
			
				
			

			
			
				
				
				
				
			

			
			
				
				
			

			
			
				
				
			

			
			
			

3.5 运行mybatis generator

从零开始建站(四) - 后端项目搭建_第8张图片

4.配置application.properties

#springboot整合mybatis
#实体类包
mybatis.type-aliases-package=com.yytf.vo
#mybatis配置文件和mapper文件位置
mybatis.mapper-locations=classpath*:mapper/*.xml

#mysql数据库连接信息
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://000.000.000.000:3306/blogs?useUnicode=true&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&
spring.datasource.username = root
spring.datasource.password = ********

spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5


#tomcat端口号
server.port=8080
server.session.timeout=10
server.tomcat.uri-encoding=UTF-8
server.context-path=/


#log4j日志配置
logging.config=classpath:log4j2.xml
#log4j打印mybatis的sql语句
#logging.level.com.yytf.dao=debug

5.springboot整合mybatis

5.1 引入依赖

在pom.xml中引入:



	org.mybatis
	mybatis
	3.4.1


	org.mybatis.spring.boot
	mybatis-spring-boot-starter
	1.3.1

		


	mysql
	mysql-connector-java
	8.0.11

5.2 在application.properties里配置:

#实体类包
mybatis.type-aliases-package=com.yytf.vo
#mybatis配置文件和mapper文件位置
mybatis.mapper-locations=classpath*:mapper/*.xml
#mysql数据库连接信息
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://000.000.000.000:3306/blogs?useUnicode=true&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&
spring.datasource.username = root
spring.datasource.password = ********

5.3 在启动类Application.java中配置mapper扫描注解

@MapperScan("com.yytf.dao")

6.springboot整合log4j

6.1 在pom.xml文件中添加log4j的jar包依赖,首先排除内置的日志工具


	
		org.springframework.boot
		spring-boot-starter-web

		
		
			
				org.springframework.boot
				spring-boot-starter-logging
			
		
	

	
	
		org.springframework.boot
		spring-boot-starter-log4j2
	

6.2 在application.properties中配置指定log4j2.xml的位置

#log4j日志配置
logging.config=classpath:log4j2.xml
#log4j打印mybatis的sql语句
#logging.level.com.yytf.dao=debug

6.3 配置log4j2.xml

下面贴上代码:解释一下

>_> LOG_HOME:这里的/var/log/blogs路径如果在linux就是对应的目录,如果在windows上则在当前盘符下新建一个var文件夹,例如tomcat在D盘,则在D盘新建路径D:\var\log\blogs

>_> FILE_NAME:临时生成的日志文件名称,下面配置中第二天会被新生成的替代

>_> Console标签:输出到控制台

>_> RollingRandomAccessFile标签:周期性生成新的日志文件并存档

>_> filePattern:存档的日志文件的命名规则,例如下面配置生成:

D:\var\log\blogs\2018-09\blogs-2018-09-15-1.log,i%代表1开始递增

>_> TimeBasedTriggeringPolicy标签:生成新文件周期数,例如下面interval="1"是一天一个日志文件

>_> SizeBasedTriggeringPolicy标签和i%是配合使用的,表示当日志文件大小超过20MB就生成新日志文件,新日志文件后缀i%就递:blogs-2018-09-15-2.log

>_> 最后一个Logger name="com.yytf.dao"是在本地调试时把sql语句打印在控制台


 
    
        /var/log/blogs
        blogs
        info
    


      
          
              
        

        
            
            
                
                
            
            
        
      

      
          
            
              
        

        
             
        
      

7.springboot使用内置定时任务

7.1 启动类Application.java

添加注解:@EnableScheduling

7.2 定时任务类

package com.yytf.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class Timer {
	@Autowired
	EverydayTalkMapper everydayTalkMapper;
	
	@Scheduled(cron = "0 59 23 * * ?")
	public void scheduleUpdateTalkId() {
		System.out.println("======>" + System.currentTimeMillis());
	}
}

7.3 使用场景

项目中每日一语需要每天变换,设置cron表达式为:cron = "0 59 23 * * ?"在每天0点前把项目中的存储每日一语的静态变量的信息更换。

8.springboot使用JWT(Java Web Token)做Token验证

8.1 为什么要使用token验证

>_> 因为我们的前后端是分离的,所有的请求都是跨域行为,所以sessionId一直是变化的,不能通过sessionId来获得用户信息

>_> 有token的时候我们只用在第一次登录的时候查询一下数据库,然后在token的过期时间内就可以不用再与数据库用户表交互,减少IO操作。

>_> 如果有多台服务器做负载均衡,因为token是无状态的,所以服务器之间可以共用token

8.2 pom.xml中引入jwt的jar包依赖


	com.auth0
	java-jwt
	2.2.0

8.3 新建Token签发与解析验证类JavaWebToken.java,注意payload里面不要存放敏感信息,例如不要存放密码等,因为该部分是对称加密,在客户端可以解密。SECRET是不能暴露出去的,相当于私钥,加密的方式由它决定。

package com.yytf.util;

import java.util.HashMap;
import java.util.Map;

import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;

public class JavaWebToken {
 
    	private static final String SECRET = "********";
    	
    	private static final String EXP = "exp";
    	
    	private static final String PAYLOAD = "payload";
     
    	public static  String sign(T object, long maxAge) {
    		try {
    			final JWTSigner signer = new JWTSigner(SECRET);
    			final Map claims = new HashMap();
    			ObjectMapper mapper = new ObjectMapper();
    			String jsonString = mapper.writeValueAsString(object);
    			claims.put(PAYLOAD, jsonString);
    			claims.put(EXP, System.currentTimeMillis() + maxAge);
    			return signer.sign(claims);
    		} catch(Exception e) {
    			return null;
    		}
    	}
    	
    	public static T unsign(String jwt, Class classT) {
    		final JWTVerifier verifier = new JWTVerifier(SECRET);
    	    try {
    			final Map claims= verifier.verify(jwt);
    			if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
    				long exp = (Long)claims.get(EXP);
    				long currentTimeMillis = System.currentTimeMillis();
    				if (exp > currentTimeMillis) {
    					String json = (String)claims.get(PAYLOAD);
    					ObjectMapper objectMapper = new ObjectMapper();
    					return objectMapper.readValue(json, classT);
    				}
    			}
    			return null;
    		} catch (Exception e) {
    			return null;
    		}
    	}
}

8.4 登录成功签发token

在loginController.java中:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.yytf.util.JavaWebToken;
import com.yytf.vo.UserVO;

@Controller
@RequestMapping(value="/login")
public class LoginController {
	@RequestMapping(value="/login",method=RequestMethod.POST)
	@ResponseBody
	public ResponseUtil login(@RequestBody UserVO userVO) {
		
		UserVO resultUserVO = new UserVO();
		String userName = PropertiesUtil.getProperty("userName");
		String password = PropertiesUtil.getProperty("password");
		if(userVO.getUserName().equals(userName) && userVO.getPassword().equals(password)) {
			Map data = new HashMap();
			resultUserVO.setUserName(userName);
			String token = JavaWebToken.sign(resultUserVO, 1000L * 3600L * 3L);
			data.put("user", resultUserVO);
			return ResponseUtil.loginSuccess(data, token);
		}
		return ResponseUtil.fail("login fail");
	}
}

8.5 访问怎删改查接口验证是否登录

前台传入token,然后验证token是否正确,如果不正确则返回前台登录界面

public class CheckIsLogin {

	/**
	 * 检查是否有操作权限
	 * @param token
	 * @return
	 */
	public static boolean checkIsLogin(String token) {
		UserVO userVO = JavaWebToken.unsign(token, UserVO.class);
		String userName = PropertiesUtil.getProperty("userName");
		if(userVO != null && userVO.getUserName().equals(userName)) {
			return true;
		}
		return false;
	}
}

9.springboot使用CORS配置解决跨域问题

package com.yytf.util;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * 全局CORS配置解决跨域问题
*/
@Configuration
public class CORSConfiguration {
	  /*方式一只支持一个域名配置*/
//	  @Bean
//    public FilterRegistrationBean corsFilter() {
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        CorsConfiguration config = new CorsConfiguration();
//        config.setAllowCredentials(true);
//        // 设置你要允许的网站域名,如果全允许则设为 *
//        config.addAllowedOrigin("*");
////       config.addAllowedOrigin("http://test.com");
//        // 如果要限制 HEADER 或 METHOD 请自行更改
//        config.addAllowedHeader("*");
//        config.addAllowedMethod("*");
//        source.registerCorsConfiguration("/**", config);
//        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
//        // 这个顺序很重要哦,为避免麻烦请设置在最前
//        bean.setOrder(0);
//        return bean;
//    }
	
	/*方式二支持多个域名*/
	@Bean
	public WebMvcConfigurer corsConfigurer() {
		return new WebMvcConfigurerAdapter() {
			@Override
			public void addCorsMappings(CorsRegistry registry) {
				registry.addMapping("/**")
		.allowedOrigins("http://test.com","http://www.test.com")
						.allowedHeaders("*")
						.allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS")
						.allowCredentials(true).maxAge(3600);
			}
		};
	}

}

三、Debug记录

1.数据正常返回,前台却报404错误,因为后台方法缺少@ResponseBody注解

从零开始建站(四) - 后端项目搭建_第9张图片

从零开始建站(四) - 后端项目搭建_第10张图片

2.mybatis中foreach标签使用参数中间缺少逗号

从零开始建站(四) - 后端项目搭建_第11张图片

从零开始建站(四) - 后端项目搭建_第12张图片

3.使用mybatis-generator生成dao,mapper时报错

从零开始建站(四) - 后端项目搭建_第13张图片

从零开始建站(四) - 后端项目搭建_第14张图片

4.使用mybatis-generator生成dao,mapper时报错

从零开始建站(四) - 后端项目搭建_第15张图片

从零开始建站(四) - 后端项目搭建_第16张图片

5.MySQL8以上(包含8)版本注意事项

在前面的配置文件里代码已经贴出

从零开始建站(四) - 后端项目搭建_第17张图片

6.Mapper和Service实例注入失败,不能被发现

从零开始建站(四) - 后端项目搭建_第18张图片

从零开始建站(四) - 后端项目搭建_第19张图片

从零开始建站(四) - 后端项目搭建_第20张图片

OJBK大概就这些了,剩下的都基本是苦力活就不说了,整个项目搞下来还是花了不少时间,超出了预期时间很多,不过也学到了不少东西。俗话说:纸上得来终觉浅,绝知此事要躬行,只用多写,多敲,多练我们才能进步的更快。我的自控力很差,玩起来就什么不管了,很难坚持一件事到底,所以我有时候想是不是要给自己每天规划一下要完成什么任务,要先坚持一个东西,比如写博客来锻炼自己的持久力,能做好一个,其它的慢慢就都能搞好了吧。渴望进步证明我还没有堕落到当一个咸鱼,哈哈,加油吧!

 

你可能感兴趣的:(建站日志)