À propos de la confusion observée dans les serveurs Java de démarrage

Dans cet article, nous examinerons certaines des façons dont ces services peuvent être mieux orientés dans les situations déroutantes rencontrées dans les serveurs Java de démarrage.

Utiliser la classe de base du contrôleur et la classe de base du service

Introduction de la classe de base

** Classe de base du contrôleur **

/** Controller Base Classes */
public class BaseController {    
    /** Injection services related */
    /** User Service */
    @Autowired
    protected UserService userService;
    ...

    /** Static constant correlation */
    /** Phone number mode */
    protected static final String PHONE_PATTERN = "/^[1]([3-9])[0-9]{9}$/";
    ...

    /** Static function related */
    /** Verify phone number */
    protected static vaildPhone(String phone) {...}
    ...
}

La classe commune basée sur le contrôleur comprend principalement les services d'injection, les constantes statiques et les fonctions statiques, et tous les contrôleurs héritent de ces ressources de la classe basée sur le contrôleur et peuvent les utiliser directement dans la fonction. Je vais.

** Classe de base de service ** La classe de base du service général est la suivante.

/** Service Base Classes */
public class BaseService {
    /** Injection DAO related */
    /** User DAO */
    @Autowired
    protected UserDAO userDAO;
    ...

    /** Injection services related */
    /** SMS service */
    @Autowired
    protected SmsService smsService;
    ...
    
    /** Injection parameters related */
    /** system name */
    @Value("${example.systemName}")
    protected String systemName;
    ...

    /** Injection constant related */
    /** super user ID */
    protected static final long SUPPER_USER_ID = 0L;
    ...

    /** Service function related */
    /** Get user function */
    protected UserDO getUser(Long userId) {...}
    ...

    /** Static function related */
    /** Get user name */
    protected static String getUserName(UserDO user) {...}
    ...
}

Les classes courantes basées sur les services sont principalement l'injection objet d'accès aux données (DAO), injection Il comprend des services, des paramètres d'injection, des constantes statiques, des fonctions de service et des fonctions statiques, et tous les services héritent de ces ressources de classes basées sur les services et peuvent être utilisés directement dans les fonctions.

Besoin d'une classe de base

Premièrement, Principe de substitution de Liskov (LSP )Regardons.

Selon le LSP, les objets de cette sous-classe doivent être disponibles de manière transparente partout qui fait référence à la classe de base (superclasse).

Ensuite, jetons un œil aux avantages de la classe de base.

  1. En ce qui concerne la classe de base, la sous-classe possède toutes les méthodes et tous les attributs de la superclasse, de sorte que la charge de travail pour la création de la sous-classe est réduite.
  2. La classe de base améliore la réutilisabilité du code car la sous-classe a toutes les fonctions de la superclasse.
  3. La classe de base améliore l'évolutivité du code car les sous-classes peuvent ajouter leurs propres fonctions.

Par conséquent, nous pouvons tirer les conclusions suivantes.

  1. Les classes basées sur le contrôleur et les classes basées sur le service ne sont utilisées directement nulle part dans le projet et ne seront pas remplacées par leurs sous-classes. Par conséquent, ils ne sont pas conformes à LSP.
  2. Les classes basées sur le contrôleur et les classes basées sur le service n'ont pas de fonctions d'interface abstraites ou de fonctions virtuelles. Autrement dit, toutes les sous-classes qui héritent de la classe de base n'ont pas de caractéristiques communes. Par conséquent, ce qui est utilisé dans le projet reste une sous-classe.
  3. La classe de base du contrôleur et la classe de base du service se concentrent uniquement sur la réutilisabilité. Cela signifie que les sous-classes peuvent facilement utiliser les ressources de classe de base telles que les DAO d'injection, les services d'injection, les paramètres d'injection, les constantes statiques, les fonctions de service et les fonctions statiques. Cependant, les classes basées sur les contrôleurs et les services ignorent la nécessité de ces ressources. Autrement dit, ces ressources ne sont pas essentielles pour la sous-classe. Par conséquent, cela ralentit les performances lorsque la sous-classe est chargée.

L'essentiel est que les classes basées sur les contrôleurs et les services appartiennent à des classes diverses. Ce ne sont pas vraiment des classes de base et doivent être divisées.

Comment diviser la classe de base

Étant donné que la classe de base de service est plus typique que la classe de base du contrôleur, cet article explique comment diviser la «classe de base» à l'aide de la classe de base de service comme exemple.

** Mettez l'instance d'injection dans la classe d'implémentation ** Injectez le DAO, les services, les paramètres, etc. à utiliser dans la classe d'implémentation selon le principe «d'introduire la classe uniquement lorsqu'elle est utilisée et de la supprimer lorsqu'elle n'est pas nécessaire».

/** Udser Service Class */
@Service
public class UserService {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;

    /** SMS service */
    @Autowired
    private SmsService smsService;

    /** System name */
    @Value("${example.systemName}")
    private String systemName;
    ...
}

** Mettez les constantes statiques dans la classe constante ** Encapsulez les constantes statiques dans la classe de constante correspondante et utilisez-les directement si nécessaire.

/** example constant class */
public class ExampleConstants {
    /** super user ID */
    public static final long SUPPER_USER_ID = 0L;
    ...
}

** Mettez la fonction de service dans la classe de service ** Encapsulez la fonction de service dans la classe de service correspondante. Si vous souhaitez utiliser une autre classe de service, vous pouvez injecter une instance de cette classe de service et appeler des fonctions de service via l'instance.

/** User service class */
@Service
public class UserService {
    /** Ger user function */
    public UserDO getUser(Long userId) {...}
    ...
}

/** Company service class */
@Service
public class CompanyService {
    /** User service */
    @Autowired
    private UserService userService;
    
    /** Get the administrator */
    public UserDO getManager(Long companyId) {
        CompanyDO company = ...;
        return userService.getUser(company.getManagerId());
    }
    ...
}

** Mettre les fonctions statiques dans la classe d'outils ** Encapsulez les fonctions statiques dans les classes d'outils correspondantes et utilisez-les directement si nécessaire.

/** User Aid Class */
public class UserHelper {
    /** Get the user name */
    public static String getUserName(UserDO user) {...}
    ...
}

Le code métier est écrit dans la classe du contrôleur

Explication du phénomène

Je vois souvent du code comme celui-ci dans la classe de contrôleur.

/** User Controller Class */
@Controller
@RequestMapping("/user")
public class UserController {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;

    /** Get user function */
    @ResponseBody
    @RequestMapping(path = "/getUser", method = RequestMethod.GET)
    public Result<UserVO> getUser(@RequestParam(name = "userId", required = true) Long userId) {
        // Get user information
        UserDO userDO = userDAO.getUser(userId);
        if (Objects.isNull(userDO)) {
            return null;
        }
        
        // Copy and return the user
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userDO, userVO);
        return Result.success(userVO);
    }
    ...
}

Le compilateur peut expliquer que vous pouvez l'écrire de cette façon car la fonction d'interface est simple et vous n'avez pas besoin d'encapsuler la fonction d'interface dans la fonction de service, mais en réalité, la fonction d'interface est encapsulée dans la fonction de service. Il n'y a pas besoin de changer.

Cas particulier

Dans ce cas particulier, le code ressemble à ceci:

/** Test Controller Class */
@Controller
@RequestMapping("/test")
public class TestController {
    /** System name */
    @Value("${example.systemName}")
    private String systemName;
    
    /** Access function */
    @RequestMapping(path = "/access", method = RequestMethod.GET)
    public String access() {
        return String.format("You're accessing System (%s)!", systemName);
    }
}

Les résultats d'accès sont les suivants.

curl http://localhost:8080/test/access

Vous accédez à System (null)!

On peut vous demander pourquoi le paramètre systemName n'a pas été injecté. À propos, le document de Spring est le suivant. Il y a une explication.

Le traitement réel de l'annotation @Value est [BeanPostProcessor](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html?spm= Notez qu'il est effectué par a2c65.11461447.0.0.7a631744QsPCA3).

L'interface BeanPostProcessor est étendue sur une base par conteneur. Cela n'est pertinent que si vous utilisez une hiérarchie de conteneurs. Si vous définissez un BeanPostProcessor dans un conteneur, ce travail est effectué uniquement pour les beans de ce conteneur. Les beans définis dans un conteneur ne sont pas post-traités par le BeanPostProcessor dans un autre conteneur, même si les deux conteneurs font partie de la même hiérarchie.

Selon ces explications, @Value est traité via BeanPostProcessor et WebApplicationContex. //docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/context/WebApplicationContext.html?spm=a2c65.11461447.0.0.7a631744QsPCA3) et [ApplicationContext](https: / /docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html?spm=a2c65.11461447.0.0.7a631744QsPCA3) est traité séparément. Par conséquent, WebApplicationContex ne peut pas utiliser la valeur d'attribut du conteneur parent.

Le contrôleur ne répond pas aux exigences du service. Par conséquent, il est inapproprié d'écrire du code métier dans la classe de contrôleur.

Architecture de serveur à trois niveaux

SpringMVC Les serveurs sont des niveaux présentation, métier, persistance Il utilise une architecture classique à trois niveaux avec des couches, utilisant @Controller, @Service et @Repository pour les annotations de classe.

image.png

--Couche de présentation: également appelée couche de contrôleur. Cette couche est chargée de recevoir les demandes des clients et de répondre aux clients avec les résultats des clients. HTTP est souvent utilisé à cette couche. --Couche commerciale: également appelée couche de service. Cette couche est responsable du traitement de la logique métier et est divisée en services et emplois par fonction.

Par conséquent, l'écriture de code métier dans la classe de contrôleur n'est pas conforme à la spécification d'architecture à trois niveaux du serveur Spring MVC.

Code de la couche de persistance vers la classe de service

Sur le plan fonctionnel, je pense qu'il est normal d'écrire le code de la couche de persistance dans la classe de service. C'est pourquoi de nombreux utilisateurs acceptent cette méthode de codage.

Problèmes principaux

  1. La couche métier et la couche de persistance sont mixtes et ne sont pas conformes aux spécifications d'architecture à 3 couches du serveur Spring MVC.
  2. La complexité de la logique métier augmente car les instructions et les clés primaires sont construites avec la logique métier.
  3. Il est difficile de remplacer le middleware de persistance tiers car le middleware tiers est utilisé directement dans la logique métier.
  4. De plus, le code de la couche de persistance du même objet est dispersé dans diverses logiques métier et [Programmation orientée objet](https://www.webopedia.com/TERM/O/object_oriented_programming_OOP.html?spm=a2c65. 11461447.0.0.7a631744Qs Contrairement au principe de PCA3).
  5. Si vous écrivez un cas de test unitaire avec cette méthode de codage, vous ne pouvez pas tester directement la fonction d'interface de la couche de persistance.

Le code de la base de données est écrit par le service

Ici, la requête directe du middleware de persistance de la base de données Hibernate est expliquée à titre d'exemple.

** Explication du phénomène **

/** User Service Class */
@Service
public class UserService {
    /** Session factory */
    @Autowired
    private SessionFactory sessionFactory;

    /** Get user function based on job number */
    public UserVO getUserByEmpId(String empId) {
        // Assemble HQL statement
        String hql = "from t_user where emp_id = '" + empId + "'";
        
        // Perform database query
        Query query = sessionFactory.getCurrentSession().createQuery(hql);
        List<UserDO> userList = query.list();
        if (CollectionUtils.isEmpty(userList)) {
            return null;
        }
        
        // Convert and return user
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userList.get(0), userVO);
        return userVO;
    }
}

** Solution recommandée **

/** User DAO CLass */
@Repository
public class UserDAO {
     /** Session factory */
    @Autowired
    private SessionFactory sessionFactory;
    
    /** Get user function based on job number */
    public UserDO getUserByEmpId(String empId) {
        // Assemble HQLstatement
        String hql = "from t_user where emp_id = '" + empId + "'";
        
        // Perform database query
        Query query = sessionFactory.getCurrentSession().createQuery(hql);
        List<UserDO> userList = query.list();
        if (CollectionUtils.isEmpty(userList)) {
            return null;
        }
        
        // Return user information
        return userList.get(0);
    }
}

/** User Service Class */
@Service
public class UserService {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;

    /** Get user function based on job number */
    public UserVO getUserByEmpId(String empId) {
        // Query user based on job number
        UserDO userDO = userDAO.getUserByEmpId(empId);
        if (Objects.isNull(userDO)) {
            return null;
        }
        
        // Convert and return user
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userDO, userVO);
        return userVO;
    }
}

** À propos des plug-ins ** AliGenerator a été développé par Alibaba [MyBatis Generator] ](Https://mybatis.org/generator/?spm=a2c65.11461447.0.0.7a631744QsPCA3) qui génère automatiquement du code pour la couche DAO (Data Access Object). Le code généré par AliGenerator vous oblige à créer des conditions de requête dans votre code métier lors de l'exécution de requêtes complexes. En conséquence, le code métier devient particulièrement gonflé.

/** User Service Class */
@Service
public class UserService {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;

    /** Get user function */
    public UserVO getUser(String companyId, String empId) {
        // Query database
        UserParam userParam = new UserParam();
        userParam.createCriteria().andCompanyIdEqualTo(companyId)
            .andEmpIdEqualTo(empId)
            .andStatusEqualTo(UserStatus.ENABLE.getValue());
        List<UserDO> userList = userDAO.selectByParam(userParam);
        if (CollectionUtils.isEmpty(userList)) {
            return null;
        }
        
        // Convert and return users
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userList.get(0), userVO);
        return userVO;
    }
}

Personnellement, je n'aime pas utiliser des plugins pour générer du code pour les couches DAO. Au lieu de cela, je préfère utiliser le MyBatis [XML] original (https://mybatis.org/mybatis-3/sqlmap-xml.html?spm=a2c65.11461447.0.0.7a631744QsPCA3) pour le mappage.

Si vous choisissez d'utiliser un plug-in, vous devriez profiter des avantages qu'il apporte tout en acceptant les inconvénients du plug-in.

Code Redis vers la classe de service

La description

/** User Service Class */
@Service
public class UserService {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;
    /** Redistemplate */
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    /** User primary key mode */
    private static final String USER_KEY_PATTERN = "hash::user::%s";

    /** Save user function */
    public void saveUser(UserVO user) {
        // Convert user information
        UserDO userDO = transUser(user);

        // Save Redis user
        String userKey = MessageFormat.format(USER_KEY_PATTERN, userDO.getId());
        Map<String, String> fieldMap = new HashMap<>(8);
        fieldMap.put(UserDO.CONST_NAME, user.getName());
        fieldMap.put(UserDO.CONST_SEX, String.valueOf(user.getSex()));
        fieldMap.put(UserDO.CONST_AGE, String.valueOf(user.getAge()));
        redisTemplate.opsForHash().putAll(userKey, fieldMap);

        // Save database user
        userDAO.save(userDO);
    }
}

** Solution recommandée **

/** User Redis Class */
@Repository
public class UserRedis {
    /** Redistemplate */
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    /** Primary key mode */
    private static final String KEY_PATTERN = "hash::user::%s";
    
    /** Save user function */
    public UserDO save(UserDO user) {
        String key = MessageFormat.format(KEY_PATTERN, userDO.getId());
        Map<String, String> fieldMap = new HashMap<>(8);
        fieldMap.put(UserDO.CONST_NAME, user.getName());
        fieldMap.put(UserDO.CONST_SEX, String.valueOf(user.getSex()));
        fieldMap.put(UserDO.CONST_AGE, String.valueOf(user.getAge()));
        redisTemplate.opsForHash().putAll(key, fieldMap);
    }
}

/** User Service Class */
@Service
public class UserService {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;
    /** User Redis */
    @Autowired
    private UserRedis userRedis;

    /** Save user function */
    public void saveUser(UserVO user) {
        //Informations pour la conversion
        UserDO userDO = transUser(user);

        // Save Redis user
        userRedis.save(userDO);

        // Save database user
        userDAO.save(userDO);
    }
}

Encapsule l'interface des opérations liées aux objets de Redis dans les classes DAO. Il adhère aux principes de programmation orientée objet du serveur Spring MVC et aux spécifications d'architecture à 3 niveaux, ce qui facilite la gestion et la maintenance du code.

La classe de modèle de base de données est exposée à l'interface

Description des symptômes

/** User DAO Class */
@Repository
public class UserDAO {
    /** Get user function */
    public UserDO getUser(Long userId) {...}
}

/** User Service Class */
@Service
public class UserService {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;

    /** Get user function */
    public UserDO getUser(Long userId) {
        return userDAO.getUser(userId);
    }
}

/** User Controller Class */
@Controller
@RequestMapping("/user")
public class UserController {
    /** User service */
    @Autowired
    private UserService userService;

    /** Get user function */
    @RequestMapping(path = "/getUser", method = RequestMethod.GET)
    public Result<UserDO> getUser(@RequestParam(name = "userId", required = true) Long userId) {
        UserDO user = userService.getUser(userId);
        return Result.success(user);
    }
}

Le code prédécesseur semble conforme à l'architecture à trois niveaux du serveur Spring MVC. Le seul problème est que le modèle de base de données UserDO est directement exposé à l'interface externe.

Problèmes existants et solutions

** Problèmes existants **

  1. La conception de la table de la base de données est exposée indirectement, ce qui est pratique pour analyser les produits concurrents.
  2. Si des restrictions de champ ne sont pas imposées aux requêtes de base de données, la quantité de données d'interface sera énorme et gaspillera un trafic utilisateur précieux.
  3. Si aucune restriction de champ n'est imposée aux requêtes de base de données, les champs sensibles peuvent facilement être exposés à l'interface, créant des problèmes de sécurité des données.
  4. Si la classe de modèle de base de données ne peut pas répondre aux exigences de l'interface, vous devez ajouter d'autres champs à la classe de modèle de base de données, ce qui entraîne une incompatibilité entre la classe de modèle de base de données et les champs de base de données.
  5. Si la documentation de l'interface n'est pas correctement gérée, la lecture du code n'aidera pas à identifier les champs de la classe de modèle de base de données utilisés par l'interface. Cela rend le code moins maintenable.

Solution

  1. Du point de vue du système de gestion, la classe de modèle de base de données doit être complètement indépendante de la classe de modèle d'interface.
  2. En raison de la structure du projet, le développeur ne doit pas exposer la classe de modèle de base de données à l'interface.

3 façons de construire un projet

Ce qui suit décrit comment créer des projets Java de manière plus scientifique pour empêcher efficacement les développeurs d'exposer des classes de modèle de base de données à l'interface.

** Méthode 1: Construisez un projet avec un modèle partagé ** Placez toutes les classes de modèle dans un projet de modèle (exemple-modèle). Tous les autres projets (exemple-référentiel, service-exemple, site-exemple, etc.) reposent sur le modèle-exemple. Le diagramme des relations est le suivant.

image.png

image.png

risque Le projet de couche de présentation (exemple-webapp) peut appeler n'importe quelle fonction de service du projet de couche de gestion (exemple-service), et la fonction DAO du projet de couche de persistance (exemple-référentiel) peut être directement appliquée à travers les couches de gestion. Vous pouvez également l'appeler.

** Méthode 2: Construisez un projet avec un modèle séparé ** Créez un projet d'API (example-api) séparément pour faire abstraction de l'interface externe et de sa classe VO modèle. Le projet de niveau métier (exemple-service) implémente ces interfaces et fournit des services au projet de niveau présentation (exemple-webapp). Le projet de couche de présentation (example-webapp) appelle uniquement les interfaces de service définies dans le projet API (example-api).

image.png

image.png

risque Le projet de niveau présentation (exemple-webapp) peut toujours appeler la fonctionnalité de service interne du projet de niveau métier (exemple-service) et la fonctionnalité DAO du projet de niveau de persistance (exemple-référentiel). Pour éviter cette situation, le système de gestion doit permettre au projet de couche présentation (example-webapp) d'appeler uniquement les fonctions d'interface de service définies par le projet API (example-api).

** Méthode 3: Construire un projet orienté services ** Empaquetez le projet de niveau métier (exemple-service) et le projet de niveau de persistance (exemple-référentiel) dans un service à l'aide du projet Dubbo (exemple-dubbo). Fournit une fonctionnalité d'interface définie dans le projet d'API (example-api) pour les projets de couche de gestion (exemple-webapp) ou d'autres projets d'entreprise (autre service).

image.png

image.png

Remarque: Le projet Dubbo (exemple-dubbo) ne libère que l'interface de service définie dans le projet API (exemple-api). Cela garantit que le modèle de base de données n'est pas exposé. Les projets de couche métier (par exemple, webapp) et d'autres projets d'entreprise (par exemple, d'autres services) dépendent uniquement des projets API (par exemple, api) et ne peuvent appeler que les interfaces de service définies dans les projets API.

Suggestions moins recommandées

Certains utilisateurs peuvent avoir les considérations suivantes: Étant donné que le modèle d'interface et le modèle de couche persistante sont séparés, si le modèle d'interface définit la classe VO du modèle de requête de données, le modèle de couche persistante doit également définir la classe DO du modèle de requête de données. Il y aura. De plus, si le modèle d'interface définit la classe VO du modèle de retour de données, le modèle de couche de persistance doit également définir la classe DO du modèle de retour de données. Cependant, cela n'est pas bien adapté pour un développement itératif rapide au début du projet. En outre, les questions suivantes se posent également. Est-il possible de laisser la couche de persistance utiliser le modèle de données d'interface sans exposer le modèle de données de couche de persistance via l'interface?

Cette méthode est inacceptable car elle affecte l'indépendance de l'architecture à trois niveaux du serveur Spring MVC. Cependant, cette méthode n'expose pas la classe de modèle de base de données et est acceptable pour un développement itératif rapide. C'est donc une proposition moins recommandée.

/** User DAO Class */
@Repository
public class UserDAO {
    /** Calculate user function */
    public Long countByParameter(QueryUserParameterVO parameter) {...}
    /** Query user function */
    public List<UserVO> queryByParameter(QueryUserParameterVO parameter) {...}
}

/** User Service Class */
@Service
public class UserService {
    /** User DAO */
    @Autowired
    private UserDAO userDAO;

    /** Query user function */
    public PageData<UserVO> queryUser(QueryUserParameterVO parameter) {
        Long totalCount = userDAO.countByParameter(parameter);
        List<UserVO> userList = null;
        if (Objects.nonNull(totalCount) && totalCount.compareTo(0L) > 0) {
            userList = userDAO.queryByParameter(parameter);
        }
        return new PageData<>(totalCount, userList);
    }
}

/** User Controller Class */
@Controller
@RequestMapping("/user")
public class UserController {
    /** User service */
    @Autowired
    private UserService userService;

    /** Query user function (with the page index parameters of startIndex and pageSize) */
    @RequestMapping(path = "/queryUser", method = RequestMethod.POST)
    public Result<PageData<UserVO>> queryUser(@Valid @RequestBody QueryUserParameterVO parameter) {
        PageData<UserVO> pageData = userService.queryUser(parameter);
        return Result.success(pageData);
    }
}

Conclusion

Chacun a ses propres opinions sur la façon de tirer parti de Java, et bien sûr cet article ne donne que mon opinion personnelle. Mais pour moi, j'ai pensé qu'il était important d'exprimer mes pensées sur la base de mon expérience avec certaines des startups pour lesquelles j'ai travaillé auparavant. Parce que, à ma connaissance, si ces configurations chaotiques sont corrigées, tout le système sera meilleur.

Recommended Posts

À propos de la confusion observée dans les serveurs Java de démarrage
À propos de l'idée des classes anonymes en Java
Une histoire sur le JDK à l'ère de Java 11
Pensez au problème JAVA = JAVAscript (nécessaire à l'avenir)
À propos de la classe abstraite Java
Découvrez les spécifications tout en raccourcissant FizzBuzz écrit en Java
Pensez aux différences entre les fonctions et les méthodes (en Java)
Devinez le code de caractère en Java
À propos du symbole <%%> dans Rails erb
Spécifiez l'emplacement Java dans eclipse.ini
Décompressez le fichier zip en Java
À propos de l'environnement de développement actuel (Java 8)
Analyser l'analyse syntaxique de l'API COTOHA en Java
A propos du traitement de la copie de fichiers en Java
Appelez la super méthode en Java
A propos du renvoi d'une référence dans un Java Getter
Obtenez le résultat de POST en Java
Devinez le cadre de persistance Java 2017 (3) Reladomo
Référence Java à comprendre dans la figure
Essayez d'utiliser l'API Stream en Java
Appelez l'API de notification Windows en Java
À propos de la procédure pour que Java fonctionne
[Création] Un mémorandum sur le codage en Java
À propos du nouveau modèle de version de Java @ Seki Java (20/07/2018)
J'ai essayé le nouveau yuan à Java
[Java] Utiliser la technologie cryptographique avec les bibliothèques standard
Organisation des notes dans la tête (Java-Arrangement)
Essayez d'appeler le service CORBA sur Java 11+
À propos des enregistrements ajoutés pour l'aperçu dans Java JDK 14
Quelle est la méthode principale en Java?
Comment obtenir la date avec Java
Discussion continue sur l'écriture de Java avec Emacs @ 2018
À propos du phénomène que StackOverflowError se produit lors du traitement à l'aide d'expressions régulières Java
L'histoire de l'écriture de Java dans Emacs
Entrée de la console en Java (comprendre le mécanisme)
Impressions et doutes sur l'utilisation de Java pour la première fois dans Android Studio
À propos de la signification des variables de type, E, T, etc. utilisées dans les génériques utilisés en Java
Concernant les modificateurs transitoires et la sérialisation en Java
L'histoire de la comparaison de chaînes de bas niveau en Java
[Java] Gestion des Java Beans dans la chaîne de méthodes
L'histoire de la fabrication d'un Othello ordinaire à Java
A propos de l'ordre de description des propriétés système Java
ChatWork4j pour l'utilisation de l'API ChatWork en Java
Mémo organisé dans la tête (syntaxe Java --Control)
Essayez de gratter environ 30 lignes en Java (sortie CSV)
Le type d'intersection introduit dans Java 10 est incroyable (?)
L'histoire de l'apprentissage de Java dans la première programmation
Mesurer la taille d'un dossier avec Java
À propos de var utilisé en Java (type de variable locale)
Ressentez le passage du temps même à Java
Organisation des notes dans la tête (Java - édition d'instance)
[Java] Lire les fichiers dans src / main / resources
Mémo organisé dans la tête (Java - type de données)
Afficher "Hello World" dans le navigateur à l'aide de Java
[Java] Jugement en saisissant des caractères dans le terminal
Afficher "Hello World" dans le navigateur à l'aide de Java
Essayez d'utiliser l'analyse syntaxique de l'API COTOHA en Java
[Java] Quelque chose est affiché comme "-0.0" dans la sortie
Importer des fichiers de la même hiérarchie en Java
À propos de l'interface Java
[Java] À propos des fonctionnalités de Java 12