主动获取
@SpringBootApplication
public class CommunityApplication {
public static void main(String[] args) {
SpringApplication.run(CommunityApplication.class, args);
}
}
配置类,启动时自动扫描,扫描配置类所在的包以及子包下的Bean.
@Component @Repository @Service @Controller
测试代码要以其为配置类,需加上注解:
@ContextConfiguration(classes = CommunityApplication.class)
想要使用spring容器需要实现接口,ApplicationContextAware,实现接口中set方法.传入参数applicationContext(spring容器),他是一个接口,继承自BeanFactory.
获取Bean:applicationContext.getBean(test.class);
public class CommunityApplicationTests implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
给Bean自定义名字:@Component(“名字”)
初始化方法@PostConstruct,在构造器之后调用.销毁对象之前调用,@PreDestroy.
@Scope()指定单例多例
@Configuration配置类,用以装载使用第三方类.
@Autowired
private AlphaService alphaService;
@Autowired
private SimpleDateFormat simpleDateFormat;
@Autowired // 表示把Alphadao属性注入到alphaDao中 通常在属性前注入
@Qualifier("alphaHibernate")
private AlphaDao alphaDao;
@Test
public void testDI(){
System.out.println(alphaDao);
System.out.println(alphaService);
System.out.println(simpleDateFormat);
}
}
// 在service层调用dao(数据库)
@Autowired
private AlphaDao alphaDao;
public String find(){
return alphaDao.select();
}
@Autowired
private AlphaService alphaService;
@RequestMapping("/data")
@ResponseBody
public String getData(){
return alphaService.find();
}
视图层的两部分代码一部分在controller里,一部分在resources.templates里
@RequestMapping("/http")
public void http(HttpServletRequest request, HttpServletResponse response) {
// 通过request获取请求数据
//请求方式
System.out.println(request.getMethod());
System.out.println(request.getServletPath());
// 获取header的key值
Enumeration<String> enumeration = request.getHeaderNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
String value = request.getHeader(name);
System.out.println(name + ":" + value);
}
System.out.println(request.getParameter("code"));
// 返回响应数据
// 返回网页
response.setContentType("text/html;charset=utf-8");
// 获取输出流
try (
PrintWriter writer = response.getWriter();
){
writer.write("牛客网
");
} catch (IOException e) {
e.printStackTrace();
}
}
// /students?current=1&limit=20 - 当前页为第一页,每一页有20条数据
@RequestMapping(path = "/students", method = RequestMethod.GET)
@ResponseBody
public String getStudents(
// 表示Request中名为current的参数赋给current, 可以不传参数进来,如果不传,默认值为1
@RequestParam(name = "current", required = false, defaultValue = "1") int current,
@RequestParam(name = "limit", required = false,defaultValue = "1") int limit){
System.out.println(current);
System.out.println(limit);
return "some students";
}
// /student/123 - 参数成为路径的一部分
@RequestMapping(path = "/student/{id}", method = RequestMethod.GET)
@ResponseBody
public String getStudent(@PathVariable("id") int id){
System.out.println(id);
return "a student";
}
必须要有表单信息,通过提交表单信息向浏览器发送请求 静态资源放在static,动态资源放在templates里,保证函数的参数与表单的name一致
student.html
<form method="post" action="/community/alpha/student">
<p>
姓名:<input type="text" name="name">
p>
<p>
年龄:<input type="text" name="age">
p>
<p>
<input type="submit" value="保存">
p>
form>
@RequestMapping(path = "/student", method = RequestMethod.POST)
@ResponseBody
public String saveStudent(String name, int age){
System.out.println(name);
System.out.println(age);
return "success";
}
@RequestMapping(path = "/teacher", method = RequestMethod.GET)
// 返回model数据和视图数据,交给模板引擎进行渲染
public ModelAndView getTeacher(){
ModelAndView mav = new ModelAndView();
mav.addObject("name", "张三");
mav.addObject("age", 40);
mav.setViewName("/demo/view");
return mav;
}
@RequestMapping(path = "/school", method = RequestMethod.GET)
// 实例化model对象,直接返回view
public String getSchool(Model model){
model.addAttribute("name", "北京大学");
model.addAttribute("age", 80);
return "/demo/view";
}
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Teachertitle>
head>
<body>
<p th:text="${name}">p>
<p th:text="${age}">p>
body>
html>
响应JSON数据,通常在异步请求中
异步请求:当前网页不刷新,但是访问服务器得到结果(客户端返回局部验证的结果:成功还是失败)
Java对象 -> JSON字符串 -> JS对象(JSON对象很常用,字符串的形式)
@RequestMapping(path = "/emp", method = RequestMethod.GET)
@ResponseBody // 必须要加,不加的话返回html
public Map<String, Object> getEmp(){
Map<String, Object> emp = new HashMap<>();
emp.put("name", "张三");
emp.put("age", 23);
emp.put("salary", 8000.00);
return emp;
}
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.0.1version>
dependency>
#DataSourceProperties 配置的是mysql数据库和连接池
#记得改自己的密码
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/community?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong
spring.datasource.username=root
spring.datasource.password=lihonghe
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=30000
#MybatisProperties
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.nowcoder.community.entity
mybatis.configuration.useGeneratedKeys=true
mybatis.configuration.mapUnderscoreToCamelCase=true
#logger 把日志级别降低,设为debug,便于输出更多的信息找错
logging.level.com.nowcoder.community=debug
User.java
public class User {
private int id;
private String username;
private String password;
private String salt;
private String email;
private int type;
private int status;
private String activationCode;
private String headerUrl;
}
@Mapper // 标识为mapper接口
public interface UserMapper {
/**
* 根据需求写接口:
* 1. 根据id、name、Email查询User
* 2. 插入id,
* 3. 根据id和xx更新Status、Header、password
*/
User selectById(int id);
User selectByName(String username);
User selectByEmail(String email);
int insertUser(User user);
int updateStatus(int id, int status);
int updateHeader(int id, String headerUrl);
int updatePassword(int id, String password);
}
在resources里的mapper包提供一个配置文件,为接口中的每一个方法提供一个sql语句
在https://mybatis.org/mybatis-3/ 里找
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nowcoder.community.dao.UserMapper">
<sql id="selectFields">
id, username, password, salt, email, type, status, activation_code, header_url, create_time
sql>
<sql id="insertFields">
username, password, salt, email, type, status, activation_code, header_url, create_time
sql>
<select id="selectById" resultType="User">
select <include refid="selectFields">include>
from user
where id = #{id}
select>
<select id="selectByName" resultType="User">
select <include refid="selectFields">include>
from user
where username = #{username}
select>
<select id="selectByEmail" resultType="User">
select <include refid="selectFields">include>
from user
where email = #{email}
select>
<insert id="insertUser" parameterType="User" keyProperty="id">
insert into user (<include refid="insertFields">include>)
values (#{username}, #{password}, #{salt}, #{email}, #{type}, #{status}, #{activationCode}, #{headerUrl}, #{createTime})
insert>
<update id="updateStatus">
update user set status = #{status} where id = #{id}
update>
<update id="updateHeader">
update user set header_url = #{headerUrl} where id = #{id}
update>
<update id="updatePassword">
update user set password = #{password} where id = #{id}
update>
mapper>
MapperTests.java
@RunWith(SpringRunner.class)
@SpringBootTest
// 在测试代码中启用CommunityApplication作为测试类
@ContextConfiguration(classes = CommunityApplication.class)
public class MapperTests {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectUser(){
User user = userMapper.selectById(101);
System.out.println(user);
user = userMapper.selectByName("liubei");
System.out.println(user);
user = userMapper.selectByEmail("[email protected]");
System.out.println(user);
}
@Test
public void testInsertUser() {
User user = new User();
user.setUsername("test");
user.setPassword("123456");
user.setSalt("abc");
user.setEmail("[email protected]");
user.setHeaderUrl("http://www.nowcoder.com/101.png");
user.setCreateTime(new Date());
int rows = userMapper.insertUser(user);
System.out.println(rows);
System.out.println(user.getId());
}
@Test
public void updateUser() {
int rows = userMapper.updateStatus(150, 1);
System.out.println(rows);
rows = userMapper.updateHeader(150, "http://www.nowcoder.com/102.png");
System.out.println(rows);
rows = userMapper.updatePassword(150, "hello");
System.out.println(rows);
}
@ 后面是填写路径的, $ 后面是填写变量数据的,#是mapper的写法,表示获取传入的参数值
public class DiscussPost {
private int id;
private int userId;
private String title;
private String content;
private int type;
private int status;
private Date createTime;
private int commentCount;
private double score;
}
@Mapper
public interface DisscussPostMapper {
// 将来会开发一个个人主页的功能,需要用到userid
// 当userid==0,就不把这个条件拼到sql里;否则就把它拼到sql里(考虑个人主页的情况) --> 动态sql
// 还需要考虑未来分页的可能: offset: 每页起始行的行号;limit: 每页最多多少条数据
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);
// 查询表中一共有多少条数据,查询帖子的行数
// param注解用来给参数起别名,如果这个方法中需要动态的参数,并且这个方法有且只有一个条件,这时候必须加@param注解,
int selectDiscussPostRows(@Param("userId") int userId);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nowcoder.community.dao.DisscussPostMapper">
<sql id="selectFields">
id, user_id, title, content, type, status, create_time, comment_count, score
sql>
<select id="selectDiscussPosts" resultType="DiscussPost">
select <include refid="selectFields">include>
from discuss_post
where status != 2
<if test="userId!=0">
and user_id = #{userId}
if>
order by type desc, create_time desc
limit #{offset }, #{limit}
select>
<select id="selectDiscussPostRows" resultType="int">
select count(id)
from discuss_post
where status != 2
<if test="userId!=0">
and user_id = #{userId}
if>
select>
mapper>
@Test
public void testSelectPosts(){
List<DiscussPost> list = disscussPostMapper.selectDiscussPosts(0, 0, 10);
for(DiscussPost discussPost : list){
System.out.println(discussPost);
}
int rows = disscussPostMapper.selectDiscussPostRows(0);
System.out.println(rows);
}
@Service
public class DiscussPostService {
// service层要调用mapper的方法,因此先要注入
// 为了减少耦合性,必须严格地按照这样的方法调用,而不是直接用mapper的方法
@Autowired
private DisscussPostMapper discussPostMapper;
public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit){
return discussPostMapper.selectDiscussPosts(userId, offset, limit);
}
public int findDiscussPostRows(int userId) {
return discussPostMapper.selectDiscussPostRows(userId);
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* 查询到的结果返回的是userid,但是在页面上需要显示的是用户名
* userid是一个外键,用来关联user表
* 这个函数针对得到的每一个discusspost查询user,和discusspost组合在一起返回给页面
*/
public User findUserById(int id){
return userMapper.selectById(id);
}
}
@RequestMapping(path = "/index", method = RequestMethod.GET)
// 最终返回的是/index
public String getIndexPage(Model model, Page page) {
// 方法调用前,SpringMVC会自动实例化Model和Page,并将Page注入Model.
// 所以,在thymeleaf中可以直接访问Page对象中的数据.
page.setRows(discussPostService.findDiscussPostRows(0));
page.setPath("/index");
List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getoffset(), page.getLimit());
List<Map<String, Object>> discussPosts = new ArrayList<>();
if(list != null){
for(DiscussPost post : list){
Map<String, Object> map = new HashMap<>();
map.put("post", post);
User user = userService.findUserById(post.getUserId());
map.put("user", user);
discussPosts.add(map);
}
}
model.addAttribute("discussposts", discussPosts);
return "/index";
}
注意:需要对方法做判断,需要添加新的方法:获得当前起始行、总页数、起始页码、结束页码
通过状态码大概判断出问题在服务端还是客户端,然后再进行下一步调试
常见的状态码:
Springboot默认使用的日志工具是logback
如果启动info级别后,比info级别更高的会被显示(warn、error),其它的会被忽视
#logger 把日志级别降低,设为debug,便于输出更多的信息找错
logging.level.com.nowcoder.community=debug
// 实例化Logger接口,设为静态(所有地方都能用) final(不可改变)
private static final Logger logger = LoggerFactory.getLogger(LoggerTests.class);
@Test
public void testLogger() {
System.out.println(logger.getName());
logger.debug("debug log");
logger.info("info log");
logger.warn("warn log");
logger.error("error log");
}
logging.file=d:/work/data/nowcoder/community.log
在实际开发时通常把不同级别的log存在不同的文件里,并且超过一定容量要建立新文件