[从零开始Java web开发] 个人学习记录

前言

研究生阶段主要用python做神经网络模型压缩,如今工作需要,从零开始学习Java web开发(实则只看了一周)。ide: idea + maven(快速配置依赖jar包) + ssh框架,部署到tomcat,使用mysql数据库。关于环境配置这里不进行描述。记录学习过程,很多语言不专业。

Web应用概念

初次接触java web开发,第一个问题就是:为啥搞那么多东西?语言就有三个:java, jsp, sql。经过一周,实现并按需求修改了两个demo,对web开发有了粗略的认识。

用户访问web时,首先接收到服务器发送的页面(jsp编写),并与之交互。
交互过程中,服务器会接收到用户的各种操作(好像叫做请求…?),然后通过java编写的逻辑,进行服务(比如准备不同的页面内容)。
其中有些服务需要用到储存在服务器硬盘中的信息(比如用户登录需要知道服务器硬盘里是否储存了提交的用户和密码),此时就用到数据库。数据库当然可以用txt文本实现,但是当数据量大的时候,关系数据(sql)是个很好的选择。

maven,ssh,tomcat,mysql是啥

maven: 就像python需要anaconda对包进行下载与管理,maven也是为这个目的而生的。maven管理的是.jar包,这些.jar包就是别人写的库。当然也可以手工配置,比较繁琐。

ssh: 代表了web项目中用到的三个.jar包:spring, struts, hibernate。因为这三者经常一起使用,因此简化为ssh。

tomcat: web项目编译好放入tomcat,就可以通过浏览器访问。

mysql: 关系数据库。

第一个Demo

照着这个做
运行成功后,逐步分析其中的细节。

pom.xml

maven配置jar包的文件。每个下都是一个jar包。

web.xml

ssh框架个人认为应该从web.xml看起,就像从main函数看起一样。不一样的是,web.xml是个配置文件。在web.xml一般会配置spring与strusts,配置方式是指定spring与strusts对应的.xml文件。hibernate一般在spring的.xml里配置

.java文件

用来编写后端逻辑。可以看到source root文件夹java下有四个文件夹: action dao domain service。个人理解,domain里是定义实体的,与hibernate有关。
dao里是实体与数据库链接,与hibernate有关。
service里似乎只是加了一层封装,服务层,与spring有关。
action里进一步封装,与struts有关。

.jsp文件

主要编写前端UI界面,其中会与后端的.java进行数据交换。

第二个Demo

熟悉了小型Demo,现在看看一个网上商城如何实现。github地址是在eclipse上开发的,并且没有使用maven,因此需要做一定修改。以下零零散散记录一些ssh框架特点。

定义实体类

定义实体类是为了和数据库进行交互,也是后端与数据库交互的边界。随便看一个实体类Product.java:

package com.caozhihu.tmall.pojo;

import javax.persistence.*;
import java.util.Date;
import java.util.List;

@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    int id;

    @ManyToOne
    @JoinColumn(name = "cid")
    private Category category;

    @ManyToOne
    @JoinColumn(name = "sid")
    private Sellor sellor;

    private String name;
    private String subTitle;
    private float originalPrice;
    private int stock;

    @Transient
    private ProductImage firstProductImage; //@Transient表示这是一个瞬时字段,不会被保存到数据库中
    @Transient
    private List<ProductImage> productSingleImages;
    @Transient
    private List<ProductImage> productDetailImages;
    @Transient
    private int reviewCount;
    @Transient
    private int saleCount;

    public void setSellor(Sellor sellor){
        this.sellor = sellor;
    }

    public Sellor getSellor(){
        return sellor;
    }

    ...
    other get and set

@Entity表示这是个和数据库挂钩的实体类
@Table(name = “product”)表示挂钩的表是product
@Id表示这个成员变量是主键
@GeneratedValue(strategy = GenerationType.IDENTITY)表示添加是主键自动增长
@Column(name=a_name)将这个成员变量与表的一列命a_name挂钩,默认则同名。
@ManyToOne表明是外键
@JoinColumn(name = “cid”)表的一列命cid挂钩
private Category category;另一个实体类对应的表就是外键关联的表,默认与Category 的主键关联。
@Transient表明与数据库无关。

设计数据链接

本项目的数据链接非常简单

package com.caozhihu.tmall.dao.impl;

import org.springframework.orm.hibernate5.HibernateTemplate;


//定义了一个name = "dao" 的bean
public class DAOImpl extends HibernateTemplate {

}

其实,这时候就要看spring对应的xml了applicationContext.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.caozhihu.tmall.*"/>
    
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean name="ds"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/Tmall?characterEncoding=utf8&serverTimezone=GMT"/>
        <property name="username" value="root"/>
        <property name="password" value="123123"/>
    bean>

    <bean name="sf"
          class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        
        <property name="dataSource" ref="ds"/>
        
        <property name="packagesToScan">
            <list>
                <value>com.caozhihu.*value>
            list>
        property>
        <property name="hibernateProperties">
            
            <value>
                hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
                hibernate.show_sql=false
                hibernate.hbm2ddl.auto=update
            value>
        property>
    bean>

    <bean id="dao" class="com.caozhihu.tmall.dao.impl.DAOImpl">
        <property name="sessionFactory" ref="sf"/>
    bean>






    
    <bean id="transactionManager"
          class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sf"/>
    bean>

beans>

不得不说一句,bean就是指类的实例,只是些类有特殊的规范,所以他们的实例叫做bean。beans包裹下就是一些实例。

  1. 第一个bean叫做ds,是org.springframework.jdbc.datasource.DriverManagerDataSource类的实例,通过property对成员变量赋值,完成和数据库的连接。
  2. sf,hibernate的一个类的实例,成员变量包含了ds,并通过packagesToScan扫描所有.java文件。完成了数据库与实体类的对接。
  3. dao,就是上面写的DAOImpl的实例。成员变量有sf。这样写后就可以通过dao去进行所有的数据库操作了。
  4. 最后,transactionManager也是有sf成员变量,似乎是spring进行事务同步用的。

Service服务

本质上说,有了DAO就可直接与前端进行交互了,进行Action的编写。但是这样会有很多冗余并且比较乱。所以这里会对每个实体类提供一个service类。

这里关键要看ServiceDelegateDAO.java,只有这个类与实例dao和sf进行了链接,其它service类都继承了ServiceDelegateDAO,也就继承了与实例dao和sf的链接。每个service实例化时会完成链接。
其实也可以在spring的xml中,进行service的实例化并于dao实例链接,但是这里的service太多,因此这么操作比较省力。

然后随便看一个ProductServiceImpl.java

  1. @Service(“productService”)就是实例化了一个bean,也可以写在.xml里。
  2. @Autowired指于某个实例进行自动连接。

现在,spring里应该有很多service类的实例(大家都叫做bean,可以但没必要)

Action

项目里用了很多继承,其实是一个接着一个的,完全可以写在一个类里。读起来比较累,但是维护起来就很舒服。直接从Action4Pojo看起

  1. Action4Pojo定义了实体类的实例。
  2. Action4Service定义了服务类的实例,并用@Autowired与spring里的类完成连接。
  3. Action4Parameter定义了一些与数据库无关或不直接相关的变量。
  4. Action4Result空的,主要通过@Result()定义跳转地址
  5. ForeAction定义了很多带@Action注释的函数,是后端与前端的边界。(其它action似乎是admin有关的,没看。。)

前端

无参跳转,后端准备数据

网站默认进入index.jsp(欢迎页,web.xml里配置)。上来就是

response.sendRedirect("fore2home");

触发ForeAction里

@Action("fore2home")
public String home() {
    categories = categoryService.list();
    productService.fill(categories);//为每个category来设置setFirstProductImage()
    productService.fillByRow(categories);//为每个product设置setFirstProductImage(),再为每个category来setProductsByRow(products)
    return "home.jsp";
}

这里就出现了第一个交互!跳转。

home准备好资源后,显示home.jsp。注意,虽然返回home.jsp,其实这是要在Action4Result里通过@Result注册的(自己找找)。

这里就出现了第二个交互!后端送给前端categories,并且所有的service都连接上数据库了。

表格跳转(前端数据给后端)

比如搜索栏

<form action="foresearch" method="post">
        <div class="searchDiv">
            <input name="keyword" type="text" value="" placeholder="时尚喵喵鞋  喵阳镜">
            <button type="submit" class="searchButton">搜索</button>
        </div>
    </form>

这里的关键是keyword与foresearch。keyword是在Action4Parameter里定义的String(一定要有对应的get与se函数t),foresearch则是ForeAction中的。

@Action("foresearch")
public String search() {
    products = productService.search(keyword, 0, 20);
    productService.setSaleAndReviewNumber(products);
    for (Product product : products) {
        productImageService.setFirstProductImage(product);
    }

    return "searchResult.jsp";
    }

可以看到,直接用了keyword。

连接跳转

同样是在home.jsp包含的categoryMenu.jsp(仔细找找)

<div class="categoryMenu">
    <c:forEach items="${categories}" var="c">
        <div cid="${c.id}" class="eachCategory">
            <span class="glyphicon glyphicon-link"></span>
            <a href="forecategory?category.id=${c.id}">${c.name}</a>
        </div>
    </c:forEach>
</div>

这里有个href="forecategory?category.id= c . i d " , 比 较 特 殊 的 是 后 面 有 个 ? c a t e g o r y . i d = {c.id}",比较特殊的是后面有个?category.id= c.id"?category.id={c.id}(普通的href跳转自己找找)。
看到ForeAction

@Action("forecategory")
public String category() {
    products = productService.fill(category);//category.setProducts(products);
    //System.out.println(products.get(0).getSubTitle());
    return "category.jsp";
}

这里的category.id就是${c.id}

一些解释

这里有个奇怪的点:无论是前端送数据到后端,还是后端送数据到前端,都用了ForeAction中定义的成员变量。那么不会乱嘛?
(我记得)其实每个Action跑完,所有成员变量都会被初始化(清空)。看个栗子。

@Action("forelogin")
    public String login() throws IOException {
    
        User user_session = userService.get(user.getName(), user.getPassword());

        if (user_session == null ) {
            return "login.jsp";
        }

        ActionContext.getContext().getSession().put("user", user_session);
        return "homePage";
    }

这是登录界面跳转过来的,user.name和user.password在前端赋值传入。这里的逻辑是,根据name和password到数据库查找,找到User实例就给user_session。没找到user_session就是null,登录失败返回登录界面login.jsp。登录成功,则
ActionContext.getContext().getSession().put(“user”, user_session);并返回主页
这里就把user_session,也就登录的账户记录到session里,这样无论在哪里,都可以通过
(User) ActionContext.getContext().getSession().get(“user”)
得到这个User。没记录到session里的都会被清空。

你可能感兴趣的:([从零开始Java web开发] 个人学习记录)